From 79fb76f6446a2c30a56421754b5cef8054c074ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:54:44 +0000 Subject: [PATCH 01/99] Bump sharp from 0.30.7 to 0.32.6 Bumps [sharp](https://github.com/lovell/sharp) from 0.30.7 to 0.32.6. - [Release notes](https://github.com/lovell/sharp/releases) - [Changelog](https://github.com/lovell/sharp/blob/main/docs/changelog.md) - [Commits](https://github.com/lovell/sharp/compare/v0.30.7...v0.32.6) --- updated-dependencies: - dependency-name: sharp dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- package-lock.json | 172 ++++++++++++++++++++++++++++++++++++---------- package.json | 2 +- 2 files changed, 137 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92308eaa6..d773719a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapcomplete", - "version": "0.34.7", + "version": "0.34.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mapcomplete", - "version": "0.34.7", + "version": "0.34.9", "license": "GPL-3.0-or-later", "dependencies": { "@rgossiaux/svelte-headlessui": "^1.0.2", @@ -92,7 +92,7 @@ "prettier-plugin-tailwindcss": "^0.3.0", "read-file": "^0.2.0", "sass": "^1.58.0", - "sharp": "^0.30.5", + "sharp": "^0.32.6", "svelte": "^3.55.1", "svelte-check": "^3.0.2", "svelte-preprocess": "^5.0.1", @@ -4704,6 +4704,12 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", @@ -5898,9 +5904,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "dev": true, "engines": { "node": ">=8" @@ -6868,6 +6874,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -9144,6 +9156,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, "node_modules/node-html-parser": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.5.tgz", @@ -10035,6 +10053,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -10679,23 +10703,23 @@ } }, "node_modules/sharp": { - "version": "0.30.7", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", - "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", "dev": true, "hasInstallScript": true, "dependencies": { "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", - "semver": "^7.3.7", + "semver": "^7.5.4", "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", + "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" }, "engines": { - "node": ">=12.13.0" + "node": ">=14.15.0" }, "funding": { "url": "https://opencollective.com/libvips" @@ -10744,12 +10768,6 @@ "node": ">=10" } }, - "node_modules/sharp/node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "dev": true - }, "node_modules/sharp/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -10765,6 +10783,28 @@ "node": ">=10" } }, + "node_modules/sharp/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/sharp/node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/sharp/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -11113,6 +11153,16 @@ "node": "*" } }, + "node_modules/streamx": { + "version": "2.15.5", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.5.tgz", + "integrity": "sha512-9thPGMkKC2GctCzyCUjME3yR03x2xNo0GPKGkRw2UMYN+gqWa9uqpyNWhmsNCutU5zHmkUum0LsCRQTXUgUCAg==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -16879,6 +16929,12 @@ "proxy-from-env": "^1.1.0" } }, + "b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "babel-plugin-polyfill-corejs2": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz", @@ -17748,9 +17804,9 @@ "dev": true }, "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "dev": true }, "detective": { @@ -18485,6 +18541,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -20209,6 +20271,12 @@ } } }, + "node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, "node-html-parser": { "version": "6.1.5", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.5.tgz", @@ -20786,6 +20854,12 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -21290,18 +21364,18 @@ } }, "sharp": { - "version": "0.30.7", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", - "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", "dev": true, "requires": { "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", - "semver": "^7.3.7", + "semver": "^7.5.4", "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", + "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" }, "dependencies": { @@ -21339,12 +21413,6 @@ "yallist": "^4.0.0" } }, - "node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "dev": true - }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -21354,6 +21422,28 @@ "lru-cache": "^6.0.0" } }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -21606,6 +21696,16 @@ "resolved": "https://registry.npmjs.org/store/-/store-2.0.12.tgz", "integrity": "sha512-eO9xlzDpXLiMr9W1nQ3Nfp9EzZieIQc10zPPMP5jsVV7bLOziSFFBP0XoDXACEIFtdI+rIz0NwWVA/QVJ8zJtw==" }, + "streamx": { + "version": "2.15.5", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.5.tgz", + "integrity": "sha512-9thPGMkKC2GctCzyCUjME3yR03x2xNo0GPKGkRw2UMYN+gqWa9uqpyNWhmsNCutU5zHmkUum0LsCRQTXUgUCAg==", + "dev": true, + "requires": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/package.json b/package.json index 17496db23..0cb7090f0 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "prettier-plugin-tailwindcss": "^0.3.0", "read-file": "^0.2.0", "sass": "^1.58.0", - "sharp": "^0.30.5", + "sharp": "^0.32.6", "svelte": "^3.55.1", "svelte-check": "^3.0.2", "svelte-preprocess": "^5.0.1", From a32ab16a5ea34a970ddc39f27d726bbd5f9a3efd Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sun, 19 Nov 2023 18:11:27 +0100 Subject: [PATCH 02/99] UI test --- src/UI/Test.svelte | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/UI/Test.svelte b/src/UI/Test.svelte index 22f2d9313..47b2ce975 100644 --- a/src/UI/Test.svelte +++ b/src/UI/Test.svelte @@ -4,12 +4,8 @@ import Translations from "./i18n/Translations"; import Tr from "./Base/Tr.svelte"; import Locale from "./i18n/Locale"; + import MarkAsFavourite from "./Popup/MarkAsFavourite.svelte"; let language = Locale.language -
- - - - {$language} -
+ From f9827dd6aeabbc2f52a9cd46b1f3c683f7caeadd Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 22 Nov 2023 19:39:19 +0100 Subject: [PATCH 03/99] Feature: add favourite --- .../layers/animal_shelter/animal_shelter.json | 3 +- assets/layers/atm/atm.json | 3 +- assets/layers/bank/bank.json | 3 +- assets/layers/bench/bench.json | 48 +- assets/layers/bench_at_pt/bench_at_pt.json | 6 +- .../layers/bicycle_rental/bicycle_rental.json | 10 +- .../bicycle_tube_vending_machine.json | 60 +- assets/layers/bike_cafe/bike_cafe.json | 2 +- .../layers/bike_cleaning/bike_cleaning.json | 4 +- .../bike_repair_station.json | 2 +- assets/layers/bike_shop/bike_shop.json | 4 +- .../bike_themed_object.json | 2 +- assets/layers/cafe_pub/cafe_pub.json | 19 +- .../charging_station/charging_station.json | 4 +- assets/layers/crossings/crossings.json | 4 +- .../cycleways_and_roads.json | 6 +- .../layers/defibrillator/defibrillator.json | 4 +- .../layers/drinking_water/drinking_water.json | 3 +- assets/layers/entrance/entrance.json | 2 +- assets/layers/favourite/favourite.json | 71 ++ assets/layers/filters/filters.json | 2 +- assets/layers/food/food.json | 14 +- assets/layers/guidepost/guidepost.json | 18 +- assets/layers/ice_cream/ice_cream.json | 24 +- assets/layers/icons/icons.json | 19 +- assets/layers/note/note.json | 2 +- assets/layers/playground/playground.json | 2 +- assets/layers/questions/questions.json | 15 +- assets/layers/recycling/recycling.json | 2 +- assets/layers/route_marker/route_marker.json | 33 +- assets/layers/shops/shops.json | 12 +- assets/layers/slow_roads/slow_roads.json | 48 +- assets/layers/toilet/toilet.json | 6 +- assets/layers/trail/trail.json | 45 +- assets/layers/tree_node/tree_node.json | 6 +- assets/themes/cyclenodes/cyclenodes.json | 3 +- assets/themes/icecream/icecream.json | 6 +- .../mapcomplete-changes.json | 216 +++++- assets/themes/walkingnodes/walkingnodes.json | 45 +- langs/en.json | 9 + langs/layers/de.json | 708 +++++++++--------- langs/layers/en.json | 12 + langs/layers/es.json | 300 ++++---- langs/layers/nl.json | 12 + langs/themes/de.json | 64 +- public/css/index-tailwind-output.css | 16 +- .../Sources/FavouritesFeatureSource.ts | 157 ++++ .../Sources/NearbyFeatureSource.ts | 63 +- src/Logic/Osm/OsmPreferences.ts | 9 + src/Models/Constants.ts | 3 + .../ThemeConfig/Conversion/PrepareLayer.ts | 39 +- .../ThemeConfig/Conversion/Validation.ts | 2 +- src/Models/ThemeConfig/LayoutConfig.ts | 3 + src/Models/ThemeViewState.ts | 27 +- src/UI/Base/LogoutButton.svelte | 10 +- src/UI/Map/DynamicIcon.svelte | 26 +- src/UI/Map/DynamicMarker.svelte | 6 +- src/UI/Map/Icon.svelte | 110 +-- src/UI/Map/Marker.svelte | 8 +- src/UI/Map/ShowDataLayer.ts | 2 - src/UI/Popup/AllTagsPanel.svelte | 2 +- src/UI/Popup/MarkAsFavourite.svelte | 48 ++ src/UI/Popup/MarkAsFavouriteMini.svelte | 36 + .../TagRendering/TagRenderingMapping.svelte | 8 +- src/UI/SpecialVisualization.ts | 4 +- src/UI/SpecialVisualizations.ts | 44 +- src/UI/Test.svelte | 17 +- src/UI/ThemeViewGUI.svelte | 3 +- 68 files changed, 1641 insertions(+), 885 deletions(-) create mode 100644 assets/layers/favourite/favourite.json create mode 100644 src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts create mode 100644 src/UI/Popup/MarkAsFavourite.svelte create mode 100644 src/UI/Popup/MarkAsFavouriteMini.svelte diff --git a/assets/layers/animal_shelter/animal_shelter.json b/assets/layers/animal_shelter/animal_shelter.json index 82c782e19..aaeb7bfff 100644 --- a/assets/layers/animal_shelter/animal_shelter.json +++ b/assets/layers/animal_shelter/animal_shelter.json @@ -9,7 +9,8 @@ "description": { "en": "An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. ", "es": "Un refugio de animales es una instalación donde se llevan animales con problemas y el personal de la instalación (voluntario o no) los alimenta y cuida, rehabilitándolos y curándolos si es necesario. Esta definición incluye las perreras para perros abandonados, los criaderos para gatos abandonados, los refugios para otros animales de compañía abandonados y los centros de recuperación de la fauna salvaje. ", - "zh_Hans": "动物收容所是一个设施,将遇到麻烦的动物带到这里,设施的工作人员(志愿者或非志愿者)喂养并照顾它们,并在必要时使它们康复和治愈。该定义包括被遗弃的狗的狗舍、被遗弃的猫的猫舍、其他被遗弃的宠物的庇护所和野生动物恢复中心。 " + "zh_Hans": "动物收容所是一个设施,将遇到麻烦的动物带到这里,设施的工作人员(志愿者或非志愿者)喂养并照顾它们,并在必要时使它们康复和治愈。该定义包括被遗弃的狗的狗舍、被遗弃的猫的猫舍、其他被遗弃的宠物的庇护所和野生动物恢复中心。 ", + "de": "Ein Tierheim ist eine Einrichtung, in die notleidende Tiere gebracht werden und wo das Personal (ob freiwillig oder nicht) sie füttert und pflegt, sie rehabilitiert und bei Bedarf heilt. Diese Definition umfasst Zwinger für ausgesetzte Hunde, Katzenheime für ausgesetzte Katzen, Unterkünfte für andere ausgesetzte Haustiere und Wildtier-Auffangstationen. " }, "source": { "osmTags": "amenity=animal_shelter" diff --git a/assets/layers/atm/atm.json b/assets/layers/atm/atm.json index 42f47c3d8..fd0df6a51 100644 --- a/assets/layers/atm/atm.json +++ b/assets/layers/atm/atm.json @@ -544,7 +544,8 @@ "ca": "Aquest caixer té sortida de veu en {language():font-bold}", "cs": "Tento bankomat má řečový výstup v {language():font-bold}", "he": "לכספומט הזה יש פלט דיבור ב {language():font-bold}", - "pt_BR": "Este caixa eletrônico tem saída de fala em {language():font-bold}" + "pt_BR": "Este caixa eletrônico tem saída de fala em {language():font-bold}", + "es": "Este cajero automático tiene salida de voz en {language():font-bold}" } } } diff --git a/assets/layers/bank/bank.json b/assets/layers/bank/bank.json index 0185dc46e..865c1ec8c 100644 --- a/assets/layers/bank/bank.json +++ b/assets/layers/bank/bank.json @@ -49,7 +49,8 @@ "cs": "Má tato banka bankomat?", "he": "האם לבנק הזה יש כספומט?", "pl": "Czy ten bank ma bankomat?", - "pt_BR": "Esse banco tem caixa eletrônico?" + "pt_BR": "Esse banco tem caixa eletrônico?", + "es": "¿Este banco tiene cajero automático?" }, "mappings": [ { diff --git a/assets/layers/bench/bench.json b/assets/layers/bench/bench.json index 6db54ddd6..e237d81f0 100644 --- a/assets/layers/bench/bench.json +++ b/assets/layers/bench/bench.json @@ -865,7 +865,8 @@ "cs": "Zjištěno dnes!", "pt": "Pesquisado hoje!", "he": "נבדק היום!", - "pt_BR": "Pesquisado hoje!" + "pt_BR": "Pesquisado hoje!", + "es": "¡Encuestado hoy!" } } ], @@ -887,7 +888,8 @@ "ca": "Aquest banc té la següent inscripció:

{inscription}

", "cs": "Tato lavice má následující nápis:

{inscription}

", "pt": "Este banco tem a seguinte inscrição:

{inscription}

", - "pt_BR": "Esse banco tem a seguinte inscrição:

{inscription}

" + "pt_BR": "Esse banco tem a seguinte inscrição:

{inscription}

", + "es": "Este banco tiene la siguiente inscripción:

{inscription}

" }, "question": { "en": "Does this bench have an inscription?", @@ -897,7 +899,8 @@ "ca": "Aquest banc té una inscripció?", "cs": "Má tato lavička nápis?", "pt": "Esse banco tem inscrição?", - "pt_BR": "Esse banco tem uma inscrição?" + "pt_BR": "Esse banco tem uma inscrição?", + "es": "¿Este banco tiene una inscripción?" }, "freeform": { "key": "inscription", @@ -917,7 +920,8 @@ "ca": "Aquest banc no té cap inscripció", "cs": "Tato lavička nemá nápis", "pt": "Este banco não tem inscrição", - "pt_BR": "Esse banco não tem uma inscrição" + "pt_BR": "Esse banco não tem uma inscrição", + "es": "Este banco no tiene inscripción" }, "addExtraTags": [ "inscription=" @@ -946,7 +950,8 @@ "ca": "P. ex. en una placa, al respatller, …", "cs": "Např. na připevněné desce, v opěradle, …", "pt": "Por exemplo: em placa montada, no encosto, ...", - "pt_BR": "P. ex. em uma placa montada, no encosto, …" + "pt_BR": "P. ex. em uma placa montada, no encosto, …", + "es": "Por ejemplo, en una placa montada, en el respaldo, …" } }, { @@ -960,7 +965,8 @@ "he": "האם לספסל הזה יש אלמנט אומנותי?", "fr": "Est-ce que ce banc inclut un élément artistique ?", "pl": "Czy ta ławka ma wbudowane dzieło sztuki?", - "pt_BR": "Esse banco tem um elemento artístico?" + "pt_BR": "Esse banco tem um elemento artístico?", + "es": "¿Tiene este banco un elemento artístico?" }, "mappings": [ { @@ -977,7 +983,8 @@ "cs": "Tato lavička má integrované umělecké dílo", "he": "לספסל זה יצירת אמנות משולבת", "pl": "Ta ławka ma wbudowane dzieło sztuki", - "pt_BR": "Esse banco tem uma obra de arte integrada" + "pt_BR": "Esse banco tem uma obra de arte integrada", + "es": "Este banco tiene una obra de arte integrada" } }, { @@ -1006,7 +1013,8 @@ "ca": "Aquest banc probablement no té cap obra d'art integrada", "de": "Die Bank hat vermutlich kein integriertes Kunstwerk", "cs": "Tato lavička pravděpodobně nemá integrované umělecké dílo", - "pt_BR": "Esse banco provavelmente não tem uma obra de arte integrada" + "pt_BR": "Esse banco provavelmente não tem uma obra de arte integrada", + "es": "Este banco probablemente no tiene una obra de arte integrada" }, "hideInAnswer": true } @@ -1019,7 +1027,8 @@ "cs": "Např. má integrovaný obraz, sochu nebo jiné netriviální tvůrčí dílo", "fr": "Par ex. il intègre une peinture, statue ou autre élément non commune, travail cratif", "pl": "Np. jest na niej coś namalowane, ma rzeźbę lub inną nietrywialną pracę", - "pt_BR": "Ex. possui uma pintura integrada, estátua ou outro trabalho criativo não trivial" + "pt_BR": "Ex. possui uma pintura integrada, estátua ou outro trabalho criativo não trivial", + "es": "Por ejemplo, si lleva integrado un cuadro, una estatua u otra obra creativa no trivial" } }, { @@ -1044,7 +1053,8 @@ "cs": "Slouží tato lavička jako památník někoho nebo něčeho?", "pt": "Este banco serve como memorial para alguém ou algo?", "pl": "Czy ta ławka służy jako pomnik upamiętniający kogoś lub coś?", - "pt_BR": "Esse banco serve como memorial para alguém ou alguma coisa?" + "pt_BR": "Esse banco serve como memorial para alguém ou alguma coisa?", + "es": "¿Actúa este banco como monumento conmemorativo de alguien o algo?" }, "mappings": [ { @@ -1058,7 +1068,8 @@ "cs": "Tato lavička je pomníkem pro někoho nebo něco", "pt": "Este banco é um memorial para alguém ou algo", "pl": "Ta ławka jest pomnikiem upamiętniającym kogoś lub coś", - "pt_BR": "Esse banco é um memorial para alguém ou alguma coisa" + "pt_BR": "Esse banco é um memorial para alguém ou alguma coisa", + "es": "Este banco es un memorial para alguien o algo" }, "addExtraTags": [ "memorial=bench", @@ -1081,7 +1092,8 @@ "cs": "Tato lavička není pro někoho nebo něco památníkem", "pt": "Este banco não é um memorial para alguém ou algo", "pl": "Ta ławka nie jest pomnikiem upamiętniającym kogoś lub coś", - "pt_BR": "Esse banco não é um memorial para alguém ou alguma coisa" + "pt_BR": "Esse banco não é um memorial para alguém ou alguma coisa", + "es": "Este banco es un no memorial para alguien o algo" }, "addExtraTags": [ "memorial=" @@ -1115,7 +1127,8 @@ "ca": "és un memorial", "cs": "je památník", "he": "הוא אנדרטה", - "pt_BR": "é um memorial" + "pt_BR": "é um memorial", + "es": "es un monumento conmemorativo" } } ] @@ -1133,7 +1146,8 @@ "cs": "S opěradlem i bez něj", "he": "עם ובלי משענת גב", "pl": "Z oraz bez oparcia", - "pt_BR": "Com e sem encosto" + "pt_BR": "Com e sem encosto", + "es": "Con y sin respaldo" } }, { @@ -1147,7 +1161,8 @@ "cs": "Má opěradlo", "he": "בעל משענת גב", "pl": "Ma oparcie", - "pt_BR": "Tem um encosto" + "pt_BR": "Tem um encosto", + "es": "Tiene respaldo" } }, { @@ -1161,7 +1176,8 @@ "cs": "Nemá opěradlo", "he": "אין משענת גב", "pl": "Nie ma oparcia", - "pt_BR": "Não tem um encosto" + "pt_BR": "Não tem um encosto", + "es": "Sin respaldo" } } ] diff --git a/assets/layers/bench_at_pt/bench_at_pt.json b/assets/layers/bench_at_pt/bench_at_pt.json index 1c9f8bc4b..10fb1b0bf 100644 --- a/assets/layers/bench_at_pt/bench_at_pt.json +++ b/assets/layers/bench_at_pt/bench_at_pt.json @@ -261,7 +261,8 @@ "cs": "Na této autobusové zastávce není lavička (nikdy zde nebyla nebo byla odstraněna)", "pt": "Este ponto de ônibus não tem banco (nunca houve ou foi removido)", "pl": "Ten przystanek autobusowy nie ma ławki (nigdy jej nie było lub została usunięta)", - "pt_BR": "Essa parada de ônibus não tem um banco (nunca teve ou ele foi removido)" + "pt_BR": "Essa parada de ônibus não tem um banco (nunca teve ou ele foi removido)", + "es": "Esta parada de autobús no tiene banco (nunca lo hubo o lo han quitado)" } } ], @@ -277,7 +278,8 @@ "cs": "Tato autobusová zastávka se již nepoužívá", "pt": "Este ponto de ônibus não é mais usado", "pl": "Ten przystanek autobusowy nie jest już używany", - "pt_BR": "Essa parada de ônibus não é mais usada" + "pt_BR": "Essa parada de ônibus não é mais usada", + "es": "Esta parada ya no se usa" } } ], diff --git a/assets/layers/bicycle_rental/bicycle_rental.json b/assets/layers/bicycle_rental/bicycle_rental.json index c35c3dc51..d0ddb56ff 100644 --- a/assets/layers/bicycle_rental/bicycle_rental.json +++ b/assets/layers/bicycle_rental/bicycle_rental.json @@ -182,7 +182,7 @@ "en": "This is a rental business which rents out various objects and/or vehicles. It rents out bicycles too, but this is not the main focus", "nl": "Dit is een zaak die verschillende voorwerpen en/of voertuigen verhuurt, waaronder ook fietsen; al zijn fietsen niet de hoofdfocus", "de": "Dies ist ein Geschäft, das verschiedene Gegenstände und/oder Fahrzeuge vermietet. Es vermietet auch Fahrräder, aber das ist nicht der Hauptschwerpunkt", - "es": "Este es un negocio de alquileres que alquila varios objetos y/o vehículos. También alquila bicicletas, pero este no es el enfoque principal", + "es": "Se trata de una empresa de alquiler que alquila diversos objetos y/o vehículos. También alquila bicicletas, pero este no es el objetivo principal", "da": "Dette er en udlejningsvirksomhed, som udlejer forskellige genstande og/eller køretøjer. Den udlejer også cykler, men det er ikke det primære fokus", "fr": "C'est une agence louant diverses choses et/ou voitures. Elle loue également des vélos, mais ce n'est pas sa principale activité", "cs": "Jedná se o půjčovnu, která pronajímá různé předměty a/nebo vozidla. Pronajímá také jízdní kola, ale to není hlavní náplní", @@ -218,7 +218,7 @@ "en": "This is an automated docking station, where a bicycle is mechanically locked to a structure", "nl": "Dit is een docking station waar de fietsen mechanisch in een grotere structuur worden vastgemaakt", "de": "Dies ist eine automatisierte Radstation, bei der ein Fahrrad mechanisch an einer Struktur befestigt wird", - "es": "Esta es una estación automática, en la que una bici se asegura mecánicamente a una estructura", + "es": "Se trata de una estación de bicicletas automatizada donde una bicicleta se fija mecánicamente a una estructura", "fr": "C'est un point d’attache automatisé où le vélo est attaché mécaniquement à une structure", "da": "Dette er en automatiseret dockingstation, hvor en cykel låses mekanisk fast i en struktur", "cs": "Jedná se o automatickou dokovací stanici, kde je jízdní kolo mechanicky uzamčeno ke konstrukci", @@ -253,7 +253,7 @@ "en": "This is a dropoff point, e.g. a reserved parking to place the bicycles clearly marked as being for the rental service only", "nl": "Dit is een dropzone, bv. een fietsparkeerplaats die is voorbehouden voor fietsverhuur", "de": "Dies ist ein Rückgabepunkt, z.B. ein reservierter Parkplatz, um die Fahrräder abzustellen, die eindeutig als nur für den Verleih gekennzeichnet sind", - "es": "Este es un punto de entrega, ej. un aparcamiento reservado para colocar las bicicletas, claramente marcado como solo para el servicio de alquiler", + "es": "Se trata de un punto de entrega, por ejemplo, un aparcamiento reservado para colocar las bicicletas claramente señalizado como exclusivo para el servicio de alquiler", "fr": "C'est un point de dépôt, p.ex. un emplacement de parking réservé aux vélos de location", "da": "Dette er et afleveringssted, f.eks. en reserveret parkeringsplads til cykler, som er tydeligt markeret som værende forbeholdt udlejningstjenesten", "cs": "Jedná se o místo předání, např. vyhrazené parkoviště pro umístění jízdních kol, zřetelně označené jako místo určené pouze pro půjčovnu", @@ -519,7 +519,7 @@ "nl": "mountainbikes", "ca": "bicicletas de muntanya", "de": "Mountainbikes", - "es": "bicis de montaña", + "es": "bicicletas de montaña", "da": "mountainbike", "eo": "montobicikloj", "fr": "vélos de montagne", @@ -573,7 +573,7 @@ "de": "Wie viele type_plural können hier gemietet werden?", "fr": "Combien de type_plural peuvent être loués ici ?", "cs": "Kolik typů kol si zde můžete pronajmout?", - "es": "¿Cuántas type_plural pueden alquilarse aquí?", + "es": "¿Cuántos type_plural se pueden alquilar aquí?", "ca": "Quants type_plural es poden llogar aquí?", "pt_BR": "Quantos type_plural podem ser alugados aqui?" }, diff --git a/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json b/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json index 559b314dc..a3e405fa5 100644 --- a/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json +++ b/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json @@ -12,7 +12,8 @@ "pt": "Máquina de venda automática de tubos de bicicleta", "da": "Automat til salg af cykelslanger", "cs": "Automat na cyklistické duše", - "ca": "Màquina expenedora de tubs de bicicleta" + "ca": "Màquina expenedora de tubs de bicicleta", + "es": "Máquina expendedora de tubos de bicicleta" }, "description": { "en": "A layer showing vending machines for bicycle tubes (either purpose-built bicycle tube vending machines or classical vending machines with bicycle tubes and optionally additional bicycle related objects such as lights, gloves, locks, …)", @@ -22,7 +23,8 @@ "fr": "Une couche affichant des distributeurs automatiques de chambre à air (que ce soit des distributeurs conçus spécifiquement pour les chambres à air ou des distributeurs classiques incluant des chambres à air ainsi des objets apparentés tels que de l'éclairage pour vélo, des gants, des cadenas, ...)", "cs": "Vrstva zobrazující automaty na cyklistické duše (buď speciální automaty na cyklistické duše, nebo klasické automaty s cyklistickými dušemi a případně dalšími předměty souvisejícími s jízdními koly, jako jsou světla, rukavice, zámky, ...)", "ca": "Una capa que mostra màquines expenedores per a tubs de bicicleta (ja siguin màquines expenedores de tubs de bicicleta o màquines expenedores clàssiques amb tubs de bicicleta i opcionalment objectes addicionals relacionats amb la bicicleta com ara llums, guants, panys, ...)", - "pt_BR": "Uma camada que mostra máquinas de venda de câmaras de ar de bicicleta (sejam máquinas de venda de câmaras de ar de bicicleta específicas ou máquinas de venda clássicas com câmaras de ar de bicicleta e opcionalmente objetos relacionados a bicicletas, como luzes, luvas, travas, ...)" + "pt_BR": "Uma camada que mostra máquinas de venda de câmaras de ar de bicicleta (sejam máquinas de venda de câmaras de ar de bicicleta específicas ou máquinas de venda clássicas com câmaras de ar de bicicleta e opcionalmente objetos relacionados a bicicletas, como luzes, luvas, travas, ...)", + "es": "Una capa que muestra máquinas expendedoras de cámaras de bicicleta (ya sean máquinas expendedoras de cámaras de bicicleta especialmente diseñadas o máquinas expendedoras clásicas con cámaras de bicicleta y, opcionalmente, objetos adicionales relacionados con la bicicleta, como luces, guantes, candados, etc.)" }, "source": { "osmTags": { @@ -57,7 +59,8 @@ "de": "{name} Fahrradschlauch-Automat", "cs": "Automat na cyklistické pláště{name}", "nl": "Fietsbanden-verkoopautomaat {name}", - "pt_BR": "Máquina de venda de câmara de ar para bicicleta {name}" + "pt_BR": "Máquina de venda de câmara de ar para bicicleta {name}", + "es": "Máquina expendedora de cámaras de bicicleta {name}" } } ] @@ -118,7 +121,8 @@ "pt": "uma máquina de venda automática de tubos de bicicleta", "da": "en automat til salg af cykelslanger", "cs": "automat na cyklistické duše", - "ca": "una màquina expenedora de tubs de bicicleta" + "ca": "una màquina expenedora de tubs de bicicleta", + "es": "una máquina expendedora de tubos de bicicleta" }, "tags": [ "amenity=vending_machine", @@ -233,7 +237,8 @@ "de": "Wie viel kostet ein Fahrradschlauch?", "cs": "Kolik stojí duše na kolo?", "nl": "Hoeveel kost een fietsband?", - "pt_BR": "Quanto custa uma câmara de ar para bicicleta?" + "pt_BR": "Quanto custa uma câmara de ar para bicicleta?", + "es": "¿Cuánto cuesta una cámara para la bicicleta?" }, "render": { "en": "A bicycle tube costs {charge}", @@ -241,7 +246,8 @@ "de": "Ein Fahrradschlauch kostet {charge}", "cs": "Cena jedné duše {charge}", "nl": "Een fietsband kost {charge}", - "pt_BR": "Uma câmara de ar para bicicleta custa {charge}" + "pt_BR": "Uma câmara de ar para bicicleta custa {charge}", + "es": "Una cámara para bicicletas cuesta {charge}" }, "freeform": { "key": "charge" @@ -256,7 +262,8 @@ "de": "Welche Fahrradschläuche werden hier verkauft?", "cs": "Jaká značka duší je zde prodávána?", "nl": "Welk merk banden wordt hier verkocht?", - "pt_BR": "Quais marcas de câmara de ar são vendidas aqui?" + "pt_BR": "Quais marcas de câmara de ar são vendidas aqui?", + "es": "¿Qué cámaras se venden aquí?" }, "freeform": { "key": "brand" @@ -267,7 +274,8 @@ "de": "Hier werden Fahrradschläuche von {brand} verkauft", "cs": "{brand} duše jsou zde prodávány", "nl": "{brand} banden worden hier verkocht", - "pt_BR": "câmaras de ar {brand} são vendidas aqui" + "pt_BR": "câmaras de ar {brand} são vendidas aqui", + "es": "Las cámaras {brand} se venden aquí" }, "mappings": [ { @@ -278,7 +286,8 @@ "de": "Hier werden Fahrradschläuche von Continental verkauft", "cs": "Continental duše jsou zde prodávány", "nl": "Continental banden worden hier verkocht", - "pt_BR": "Câmaras de ar Continental são vendidas aqui" + "pt_BR": "Câmaras de ar Continental são vendidas aqui", + "es": "Las cámaras Continental se venden aquí" } }, { @@ -289,7 +298,8 @@ "de": "Hier werden Fahrradschläuche von Schwalbe verkauft", "cs": "Schwalbe duše jsou zde prodávány", "nl": "Schwalbe banden worden hier verkocht", - "pt_BR": "Câmaras de ar Schwalbe são vendidas aqui" + "pt_BR": "Câmaras de ar Schwalbe são vendidas aqui", + "es": "Las cámaras Schwalbe se venden aquí" } } ], @@ -303,7 +313,8 @@ "de": "Wer betreibt den Automaten?", "cs": "Kdo se stará o tento automat?", "nl": "Wie onderhoudt deze verkoopautomaat?", - "pt_BR": "Quem mantém essa máquina de venda?" + "pt_BR": "Quem mantém essa máquina de venda?", + "es": "¿Quién mantiene esta máquina expendedora?" }, "render": "This vending machine is maintained by {operator}", "mappings": [ @@ -315,7 +326,8 @@ "de": "Betrieben von Schwalbe", "cs": "Udržuje Schwalbe", "nl": "Onderhouden door Schwalbe", - "pt_BR": "Mantido pela Schwalbe" + "pt_BR": "Mantido pela Schwalbe", + "es": "Mantenido por Schwalbe" } }, { @@ -326,7 +338,8 @@ "de": "Betrieben von Continental", "cs": "Udržuje Continental", "nl": "Onderhouden door Continental", - "pt_BR": "Mantido pela Continental" + "pt_BR": "Mantido pela Continental", + "es": "Mantenido por Continental" } } ], @@ -343,7 +356,8 @@ "de": "Wird weiteres Fahrradzubehör verkauft?", "cs": "Prodávají se zde další doplňky na kolo?", "nl": "Worden hier andere fietsaccessoires verkocht?", - "pt_BR": "Outros acessórios para bicicleta são vendidos aqui?" + "pt_BR": "Outros acessórios para bicicleta são vendidos aqui?", + "es": "¿Se venden aquí otros accesorios para bicicletas?" }, "mappings": [ { @@ -354,7 +368,8 @@ "ca": "Aquí es venen cambres d'aire de bicicletes", "de": "Hier werden Fahrradschläuche verkauft", "cs": "Zde se prodávají cyklistické duše", - "pt_BR": "Câmaras de ar para bicicletas são vendidas aqui" + "pt_BR": "Câmaras de ar para bicicletas são vendidas aqui", + "es": "Aquí se venden cámaras de aire para bicicletas" } }, { @@ -365,7 +380,8 @@ "ca": "Aquí es venen llums per a bicicletes", "de": "Hier werden Fahrradlampen verkauft", "cs": "Zde se prodávají světla na jízdní kola", - "pt_BR": "Luzes para bicicleta são vendidas aqui" + "pt_BR": "Luzes para bicicleta são vendidas aqui", + "es": "Las luces para bicicletas se venden aquí" } }, { @@ -376,7 +392,8 @@ "ca": "Aquí es venen guants", "de": "Hier werden Fahrradhandschuhe verkauft", "cs": "Prodávají se zde rukavice", - "pt_BR": "Luvas são vendidas aqui" + "pt_BR": "Luvas são vendidas aqui", + "es": "Los guantes se venden aquí" } }, { @@ -387,7 +404,8 @@ "ca": "Aquí es venen kits de reparació de bicicletes", "de": "Hier werden Fahrrad-Reparatursets verkauft", "cs": "Zde se prodávají sady na opravu jízdních kol", - "pt_BR": "Kits para reparo de bicicleta são vendidos aqui" + "pt_BR": "Kits para reparo de bicicleta são vendidos aqui", + "es": "Los kits de reparación de bicicletas se venden aquí" } }, { @@ -398,7 +416,8 @@ "ca": "Aquí es venen bombes de bicicletes", "de": "Hier werden Fahrradpumpen verkauft", "cs": "Prodávají se zde pumpy na kolo", - "pt_BR": "Bombas de ar para bicicleta são vendidas aqui" + "pt_BR": "Bombas de ar para bicicleta são vendidas aqui", + "es": "Las bombas para bicicletas se venden aquí" } }, { @@ -409,7 +428,8 @@ "ca": "Aquí es venen cadenats per a bicicletes", "de": "Hier werden Fahrradschlösser verkauft", "cs": "Prodávají se zde zámky na kola", - "pt_BR": "Cadeados para bicicleta são vendidos aqui" + "pt_BR": "Cadeados para bicicleta são vendidos aqui", + "es": "Aquí se venden candados para bicicletas" } } ], diff --git a/assets/layers/bike_cafe/bike_cafe.json b/assets/layers/bike_cafe/bike_cafe.json index d87b439d6..17e2289fd 100644 --- a/assets/layers/bike_cafe/bike_cafe.json +++ b/assets/layers/bike_cafe/bike_cafe.json @@ -249,7 +249,7 @@ "ru": "Есть ли здесь инструменты для починки вашего велосипеда?", "pt_BR": "Há ferramentas aqui para consertar sua bicicleta?", "pt": "Há ferramentas aqui para consertar a sua própria bicicleta?", - "es": "¿Hay herramientas para reparar su propia bicicleta?", + "es": "¿Se ofrecen herramientas para reparar tu propia bicicleta?", "da": "Er der værktøj her til at reparere din egen cykel?", "cs": "Je nabízeno nářadí k opravě vlastního kola?", "ca": "S'ofereixen eines per reparar la teva pròpia bicicleta?" diff --git a/assets/layers/bike_cleaning/bike_cleaning.json b/assets/layers/bike_cleaning/bike_cleaning.json index af9737757..90eed4059 100644 --- a/assets/layers/bike_cleaning/bike_cleaning.json +++ b/assets/layers/bike_cleaning/bike_cleaning.json @@ -193,7 +193,7 @@ "en": "Free to use", "de": "Kostenlose Nutzung", "nl": "Gratis te gebruiken", - "es": "Gratis", + "es": "Uso gratuito", "fr": "Utilisation gratuite", "da": "Gratis at bruge", "cs": "Bezplatné používání", @@ -247,7 +247,7 @@ "en": "This cleaning service is free to use", "de": "Der Reinigungsservice ist kostenlos", "nl": "Dit fietsschoonmaakpunt is gratis te gebruiken", - "es": "Servicio de limpieza gratis", + "es": "Este servicio de limpieza es gratuito", "fr": "Service de nettoyage gratuit", "da": "Gratis at bruge rengøringsservice", "cs": "Tato mycí služba je bezplatná", diff --git a/assets/layers/bike_repair_station/bike_repair_station.json b/assets/layers/bike_repair_station/bike_repair_station.json index 52c89c353..81ddf1bb4 100644 --- a/assets/layers/bike_repair_station/bike_repair_station.json +++ b/assets/layers/bike_repair_station/bike_repair_station.json @@ -937,7 +937,7 @@ "it": "Sclaverand (detta anche Presta)", "ru": "Клапан Presta (также известный как французский клапан)", "da": "Sclaverand/Presta (cykeldæk med smal bredde)", - "es": "Sclaverand/Presata (ruedas de bicicleta estrechas)", + "es": "Sclaverand/Presta (neumáticos de bicicleta estrechos)", "cs": "Sclaverand/Presta (úzké cyklistické pláště)", "ca": "Sclaverand/Presta (pneumàtics per a bicis estrets)" } diff --git a/assets/layers/bike_shop/bike_shop.json b/assets/layers/bike_shop/bike_shop.json index 340c48722..6eb5e8181 100644 --- a/assets/layers/bike_shop/bike_shop.json +++ b/assets/layers/bike_shop/bike_shop.json @@ -86,7 +86,7 @@ "de": "Sportartikelgeschäft {name}", "pt_BR": "Loja de equipamentos esportivos {name}", "pt": "Loja de equipamentos desportivos {name}", - "es": "Tienda de artículos deportivos {name}", + "es": "Tienda de material deportivo {name}", "da": "Butik med sportsudstyr {name}", "ca": "Botiga d'equipament esportiu {name}", "cs": "Obchod se sportovním vybavením {name}" @@ -133,7 +133,7 @@ "de": "Fahrradverleih {name}", "pt_BR": "Aluguel de bicicletas {name}", "pt": "Aluguel de bicicletas {name}", - "es": "Alquiler de bicicletas {name}", + "es": "Tienda de alquiler de bicicletas {name}", "da": "Cykeludlejning {name}", "ca": "Botiga de lloguer de bicicletes {name}", "cs": "Půjčovna kol {name}" diff --git a/assets/layers/bike_themed_object/bike_themed_object.json b/assets/layers/bike_themed_object/bike_themed_object.json index d6e7472fe..963a5232f 100644 --- a/assets/layers/bike_themed_object/bike_themed_object.json +++ b/assets/layers/bike_themed_object/bike_themed_object.json @@ -45,7 +45,7 @@ "fr": "Objet cycliste", "de": "Fahrradbezogenes Objekt", "it": "Oggetto relativo alle bici", - "es": "Objeto relacionado con bicis", + "es": "Objeto relacionado con las bicicletas", "da": "Cykelrelateret objekt", "ca": "Objecte relacionat amb bicis", "cs": "Objekt související s jízdním kolem", diff --git a/assets/layers/cafe_pub/cafe_pub.json b/assets/layers/cafe_pub/cafe_pub.json index ec122c569..bb1417589 100644 --- a/assets/layers/cafe_pub/cafe_pub.json +++ b/assets/layers/cafe_pub/cafe_pub.json @@ -7,7 +7,7 @@ "fr": "Cafés et pubs", "zh_Hant": "咖啡廳與酒吧", "hu": "Kávézók és kocsmák", - "es": "Cafeterías y bares", + "es": "Cafeterías y pubs", "da": "Caféer og pubber", "ca": "Cafés i bars", "pl": "Kawiarnie i puby", @@ -73,19 +73,22 @@ { "if": "amenity=bar", "then": { - "en": "Bar" + "en": "Bar", + "de": "Bar" } }, { "if": "amenity=cafe", "then": { - "en": "Cafe" + "en": "Cafe", + "de": "Café" } }, { "if": "amenity=nightclub", "then": { - "en": "Nightclub" + "en": "Nightclub", + "de": "Nachtclub" } } ] @@ -213,7 +216,7 @@ "nl": "Dit is een cafe - een plaats waar men rustig kan zitten om een thee, koffie of alcoholische drank te nuttigen.", "de": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder ein alkoholisches Getränk zu trinken", "da": "En café til at drikke te, kaffe eller en alkoholisk drik i rolige omgivelser", - "es": "Una cafetería para beber té, café o una bebida alcohólica en un ambiente tranquilo", + "es": "Un café para tomar té, café o una bebida alcohólica en un ambiente tranquilo", "fr": "Un café pour prendre un thé, un café ou une boisson alcoolisée dans un environnement calme", "ca": "Una cafeteria per a a beure té, café o una beguda alcohólica en un ambient tranquil", "cs": "kavárna, kde si můžete v klidném prostředí vypít čaj, kávu nebo alkoholický nápoj" @@ -257,7 +260,7 @@ "fr": "Quel est le nom de ce pub ?", "hu": "Mi a neve ennek a kocsmának?", "da": "Hvad hedder denne pub?", - "es": "¿Cual es el nombre de este pub?", + "es": "¿Cuál es el nombre de esta empresa?", "ca": "Quin és el nom d'aquest negoci?", "cs": "Jak se tento podnik jmenuje?" }, @@ -268,7 +271,7 @@ "fr": "Ce pub se nomme {name}", "hu": "A kocsma neve: {name}", "da": "Denne pub hedder {name}", - "es": "Este pub se llama {name}", + "es": "Esta empresa se llama {name}", "ca": "Aquest negoci es diu {name}", "cs": "Tento podnik se jmenuje {name}" }, @@ -337,7 +340,7 @@ "nl": "Dit is een restaurant waar men een maaltijd geserveerd krijgt", "de": "Ein Restaurant, in dem man ordentlich essen kann", "da": "En restaurant, hvor man kan få et ordentligt måltid", - "es": "Un restaurante donde puedes comer una comida de verdad", + "es": "Un restaurante donde se pueda comer como es debido", "fr": "Un restaurant où l'on peut prendre un bon repas", "ca": "Un restaurant on es pot menjar bé", "cs": "Restaurace, kde se dá pořádně najíst" diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index 1878f1ffe..91d305c3f 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -259,7 +259,7 @@ "cs": "Nepřístupné široké veřejnosti (např. přístupné pouze majitelům, zaměstnancům, ...)", "da": "Ikke tilgængelig for offentligheden (f.eks. kun tilgængelig for ejere, ansatte, ...)", "de": "Die Station ist nicht für die Allgemeinheit zugänglich (z. B. nur für die Eigentümer, Mitarbeiter, …)", - "es": "No accesible al público general (ej. solo accesible a los propietarios, empleados, ...)" + "es": "No accesible al público en general (por ejemplo, sólo accesible a los propietarios, empleados, ...)" } }, { @@ -4343,7 +4343,7 @@ "cs": "Placené použití, ale zdarma pro zákazníky hotelu/podniku/nemocnice/..., který dobíjecí stanici provozuje", "da": "Betalt brug, men gratis for kunder på det hotel/pub/hospital/... der driver ladestationen", "de": "Die Nutzung ist kostenpflichtig, aber für Kunden des Betreibers der Einrichtung, wie Hotel, Krankenhaus, … kostenlos", - "es": "De pago, pero gratis para clientes del hotel/pub/hostpital... quien opera la estación de carga" + "es": "Pago por uso, pero gratuito para los clientes del hotel/pub/hospital/... que gestiona la estación de carga" } }, { diff --git a/assets/layers/crossings/crossings.json b/assets/layers/crossings/crossings.json index b7936f682..efe9304ba 100644 --- a/assets/layers/crossings/crossings.json +++ b/assets/layers/crossings/crossings.json @@ -7,7 +7,7 @@ "fr": "Traversée", "ca": "Encreuaments", "da": "Overgange", - "es": "Cruces", + "es": "Pasos", "pa_PK": "کراسنگاں", "cs": "Přechody" }, @@ -17,7 +17,7 @@ "de": "Übergänge für Fußgänger und Radfahrer", "fr": "Traversée pour piétons et cyclistes", "da": "Overgange for fodgængere og cyklister", - "es": "Cruces para peatones y ciclistas", + "es": "Pasos para peatones y ciclistas", "ca": "Creuaments per a vianants i ciclistes", "cs": "Přechody pro chodce a cyklisty" }, diff --git a/assets/layers/cycleways_and_roads/cycleways_and_roads.json b/assets/layers/cycleways_and_roads/cycleways_and_roads.json index a40134ee1..ad0af1e8d 100644 --- a/assets/layers/cycleways_and_roads/cycleways_and_roads.json +++ b/assets/layers/cycleways_and_roads/cycleways_and_roads.json @@ -13,7 +13,7 @@ "en": "All infrastructure that someone can cycle over, accompanied with questions about this infrastructure", "nl": "Alle infrastructuur waar je over kunt fietsen, met vragen over die infrastructuur", "de": "Infrastruktur, die man mit dem Fahrrad befahren kann, begleitet von diesbezüglichen Fragen", - "es": "Toda la infraestructura sobre la que alguien puede ir en bici, acompañado de preguntas sobre esta infraestructura\"", + "es": "Todas las infraestructuras sobre las que se puede circular en bicicleta, acompañadas de preguntas sobre las mismas", "fr": "Toutes les infrastructures sur lesquelles quelqu'un peut rouler, accompagnées de questions sur cette infrastructure", "ca": "Totes les infraestructures per les quals algú pot ciclar, acompanyades de preguntes sobre aquesta infraestructura", "cs": "Veškerá infrastruktura, kterou může někdo projet na kole, doplněná o otázky týkající se této infrastruktury" @@ -91,7 +91,7 @@ "fr": "Piste cyclable", "ca": "Via ciclista", "da": "Cykelsti", - "es": "Carril compartido", + "es": "Carril bici", "pa_PK": "سائیکل‌وے", "cs": "Cyklostezka" } @@ -121,7 +121,7 @@ "de": "Gemeinsame Fahrspur", "fr": "Voie partagée", "ca": "Carril compartit", - "es": "Vía ciclista al lado de la carretera", + "es": "Carril compartido", "cs": "Sdílený jízdní pruh" } }, diff --git a/assets/layers/defibrillator/defibrillator.json b/assets/layers/defibrillator/defibrillator.json index 07a4ea92c..23fa17507 100644 --- a/assets/layers/defibrillator/defibrillator.json +++ b/assets/layers/defibrillator/defibrillator.json @@ -253,7 +253,7 @@ "then": { "en": "Not accessible to the general public (e.g. only accesible to staff, the owners, …)", "ca": "No accessible al públic en general (ex. només accesible a treballadors, propietaris, ...)", - "es": "No accesible al público en general (ex. sólo accesible a trabajadores, propietarios, ...)", + "es": "No accesible al público en general (por ejemplo, sólo accesible para el personal, los propietarios, ...)", "fr": "Non accessible au public (par exemple réservé au personnel, au propriétaire…)", "nl": "Niet toegankelijk voor het publiek (bv. enkel voor personeel, de eigenaar, …)", "de": "Der Defibrillator ist nicht öffentlich zugänglich (z.B. nur für Personal, Eigentümer, …)", @@ -443,7 +443,7 @@ "it": "Informazioni supplementari circa la posizione (in lingua locale):
{defibrillator:location}", "de": "Zusätzliche Informationen über den Standort (in der Landessprache):
{defibrillator:location}", "sl": "Dodatne informacije o lokaciji (v lokalnem jeziku):
{defibrillator:location}", - "es": "Información a mayores sobre la localización (en el idioma local):
{defibrillator:location}", + "es": "Información adicional sobre la ubicación (en el idioma local):
{defibrillator:location}", "ca": "Informació extra sobre la localització (en la llengua local):
{defibrillator:location}", "pl": "Dodatkowe informacje o lokalizacji (w lokalnym języku):
{defibrillator:location}", "cs": "Další informace o místě (v místním jazyce):
{defibrillator:location}" diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 6baf77ad3..23dd623aa 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -108,7 +108,8 @@ "cs": "pitná voda" }, "description": { - "en": "Typically a drinking fountain, water tap, water well or natural spring" + "en": "Typically a drinking fountain, water tap, water well or natural spring", + "de": "Typischerweise ein Trinkbrunnen, Wasserhahn, Brunnen oder eine natürliche Quelle" }, "tags": [ "amenity=drinking_water" diff --git a/assets/layers/entrance/entrance.json b/assets/layers/entrance/entrance.json index 3d5f77edc..1d17bdea5 100644 --- a/assets/layers/entrance/entrance.json +++ b/assets/layers/entrance/entrance.json @@ -500,7 +500,7 @@ "en": "This door has a width of {canonical(width)}", "nl": "Deze deur heeft een breedte van {canonical(width)}", "de": "Diese Tür hat eine Durchgangsbreite von {canonical(width)}", - "es": "Esta puerta tiene una ancho de {canonical(width)} metros", + "es": "Esta puerta tiene una ancho de {canonical(width)}", "fr": "Cette porte a une largeur de {canonical(width)} mètre", "ca": "Aquesta porta té una amplària de {canonical(width)}", "cs": "Tyto dveře mají šířku {canonical(width)}" diff --git a/assets/layers/favourite/favourite.json b/assets/layers/favourite/favourite.json new file mode 100644 index 000000000..73ab80572 --- /dev/null +++ b/assets/layers/favourite/favourite.json @@ -0,0 +1,71 @@ +{ + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": { + "render": "heart", + "mappings": [ + { + "if": "_favourite=no", + "then": "heart_outline" + } + ] + }, + "color": "red" + } + ] + } + ], + "description": { + "en": "A generic map layer which shows locations that a contributor marked as favourite", + "nl": "Een laag met persoonlijke favourieten" + }, + "name": { + "en": "Favourites", + "nl": "Favorieten" + }, + "id": "favourite", + "source": "special", + "isShown": "_favourite=yes", + "minzoom": 0, + "title": { + "render": { + "en": "Favourite location", + "nl": "Favoriete locatie" + }, + "mappings": [ + { + "if": "name~*", + "then": { + "*": "{name}" + } + } + ] + }, + "tagRenderings": [ + { + "id": "Explanation", + "classes": "thanks", + "icon": { + "class": "large", + "path": "heart" + }, + "render": { + "en": "You marked this location as a personal favourite. As such, it is shown on every map you load.", + "nl": "Je hebt deze locatie als persoonlijke favoriet aangeduid en worden op alle MapComplete-kaarten getoond." + } + }, + { + "id": "show_images", + "render": { + "*": "{image_carousel()}" + } + }, + "all_tags" + ] +} diff --git a/assets/layers/filters/filters.json b/assets/layers/filters/filters.json index 20173e4eb..fafcd6dba 100644 --- a/assets/layers/filters/filters.json +++ b/assets/layers/filters/filters.json @@ -14,7 +14,7 @@ "nl": "Nu open", "de": "Jetzt geöffnet", "ca": "Obert ara", - "es": "Abierta ahora", + "es": "Abierto", "fr": "Ouvert maintenant", "hu": "Most nyitva van", "da": "Åbent nu", diff --git a/assets/layers/food/food.json b/assets/layers/food/food.json index 41248ae39..138498c46 100644 --- a/assets/layers/food/food.json +++ b/assets/layers/food/food.json @@ -247,7 +247,7 @@ "nl": "Wat is de naam van deze eetgelegenheid?", "en": "What is the name of this business?", "de": "Was ist der Name dieses Unternehmens?", - "es": "¿Cual es el nombre de este restaurante?", + "es": "¿Cuál es el nombre de este negocio?", "fr": "Quel est le nom de ce restaurant ?", "ca": "Quin és el nom d'aquest negoci?", "cs": "Jak se tento podnik jmenuje?" @@ -256,7 +256,7 @@ "nl": "De naam van deze eetgelegeheid is {name}", "en": "The name of this business is {name}", "de": "Dieses Unternehmen heißt {name}", - "es": "El nombre de este restaurante es {name}", + "es": "El nombre de este negocio es {name}", "fr": "Le nom de ce restaurant est {name}", "ca": "El nom d'aquest negoci és {name}", "cs": "Název tohoto podniku je {name}" @@ -283,7 +283,7 @@ "en": "This is a fast-food business, focused on fast service. If seating is available, it is rather limited and functional.", "nl": "Dit is een fastfood-zaak. De focus ligt op snelle bediening, zitplaatsen zijn vaak beperkt en functioneel.", "de": "Es handelt sich um einen Schnellimbiss, mit Fokus auf schnelle Bedienung am Tresen. Sitzmöglichkeiten sind begrenzt und funktional.", - "es": "Este es un negocio de comida rápida, centrado en servicio rápido. Si hay asientos disponibles, son más bien limitados y funcionales.", + "es": "Se trata de un negocio de comida rápida, centrado en el servicio rápido. Si hay asientos disponibles, son más bien limitados y funcionales.", "fr": "C'est un fast-food, centrée sur le service rapide. Si des places sont disponibles, elles sont plutôt limitées et fonctionnelles.", "hu": "Ez egy gyorsétterem (büfé), amely a gyors kiszolgálásra összpontosít. Ha vannak is ülőhelyek, ezek meglehetősen korlátozottak és funkcionálisak.", "ca": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seràn limitats i funcionals.", @@ -296,7 +296,7 @@ "en": "A restaurant, focused on creating a nice experience where one is served at the table", "nl": "Dit is een restaurant. De focus ligt op een aangename ervaring waar je aan tafel wordt bediend", "de": "Es handelt sich um ein Restaurant, mit Fokus auf eine nette Atmosphäre und Tischbedienung", - "es": "Un restaurante, centrado en crear una buena experiencia donde se sirve en la mesa", + "es": "Un restaurante, centrado en crear una experiencia agradable en la que uno se sirve en mesa", "fr": "Un restaurant, axé sur la création d'une expérience agréable où l'on est servi à table", "ca": "Un restaurant, centrat en crear una bona experiència on es serveix a taula", "cs": "Restaurace zaměřená na vytvoření příjemného zážitku, kde se obsluhuje u stolu" @@ -317,7 +317,7 @@ "nl": "Welk soort gerechten worden hier geserveerd?", "en": "What kind of food is served here?", "de": "Was für Essen gibt es hier?", - "es": "¿Qué comida se sirve aquí?", + "es": "¿Qué tipo de comida sirven aquí?", "fr": "Quelle type de nourriture est servie ici ?", "ca": "Quin menjar es serveix aquí?", "cs": "Jaké jídlo se zde podává?" @@ -442,7 +442,7 @@ "en": "This is an Italian restaurant (which serves more than pasta and pizza)", "nl": "Dit is een Italiaans restaurant (dat meer dan enkel pasta of pizza verkoopt)", "de": "Dies ist ein italienisches Restaurant (das mehr als nur Pasta und Pizza serviert)", - "es": "Este es un restaurante italiano (que sirve más que pasta y pizza)", + "es": "Este es un restaurante italiano (que sirve algo más que pasta y pizza)", "fr": "C'est un Restaurant Italien (qui sert plus que des pâtes et des pizzas)", "ca": "Això és un restaurant italià (que serveix més que pasta i pizza)", "cs": "Toto je italská restaurace (která nabízí více než těstoviny a pizzu)" @@ -588,7 +588,7 @@ "nl": "Biedt deze zaak een afhaalmogelijkheid aan?", "en": "Does this place offer take-away?", "de": "Werden Gerichte zum Mitnehmen angeboten?", - "es": "¿Este lugar ofrece para llevar?", + "es": "¿Este local ofrece comida para llevar?", "fr": "Cet établissement propose-t-il des plats à emporter ?", "ca": "Aquest lloc ofereix per a emportar?", "cs": "Nabízí toto místo jídlo s sebou?" diff --git a/assets/layers/guidepost/guidepost.json b/assets/layers/guidepost/guidepost.json index f96f0a53a..a3bfcd696 100644 --- a/assets/layers/guidepost/guidepost.json +++ b/assets/layers/guidepost/guidepost.json @@ -59,7 +59,8 @@ { "id": "type", "question": { - "en": "What kind of routes are shown on this guidepost?" + "en": "What kind of routes are shown on this guidepost?", + "de": "Welche Arten von Routen werden auf diesem Wegweiser angezeigt?" }, "multiAnswer": true, "mappings": [ @@ -67,35 +68,40 @@ "if": "bicycle=yes", "ifnot": "bicycle=", "then": { - "en": "This guidepost shows bicycle routes" + "en": "This guidepost shows bicycle routes", + "de": "Dieser Wegweiser zeigt Fahrradrouten" } }, { "if": "hiking=yes", "ifnot": "hiking=", "then": { - "en": "This guidepost shows hiking routes" + "en": "This guidepost shows hiking routes", + "de": "Dieser Wegweiser zeigt Wanderwege" } }, { "if": "mtb=yes", "ifnot": "mtb=", "then": { - "en": "This guidepost shows mountain bike routes" + "en": "This guidepost shows mountain bike routes", + "de": "Dieser Wegweiser zeigt Mountainbike-Routen" } }, { "if": "horse=yes", "ifnot": "horse=", "then": { - "en": "This guidepost shows horse riding routes" + "en": "This guidepost shows horse riding routes", + "de": "Dieser Wegweiser zeigt Reitwege" } }, { "if": "ski=yes", "ifnot": "ski=", "then": { - "en": "This guidepost shows ski routes" + "en": "This guidepost shows ski routes", + "de": "Dieser Wegweiser zeigt Skirouten" } } ] diff --git a/assets/layers/ice_cream/ice_cream.json b/assets/layers/ice_cream/ice_cream.json index da26f3656..b6d6576a9 100644 --- a/assets/layers/ice_cream/ice_cream.json +++ b/assets/layers/ice_cream/ice_cream.json @@ -1,23 +1,27 @@ { "id": "ice_cream", "name": { - "en": "Ice cream parlors" + "en": "Ice cream parlors", + "de": "Eisdielen" }, "description": { - "en": "A place where ice cream is sold over the counter" + "en": "A place where ice cream is sold over the counter", + "de": "Ein Ort, an dem Eiscreme an der Theke verkauft wird" }, "source": { "osmTags": "amenity=ice_cream" }, "title": { "render": { - "en": "Ice cream parlor" + "en": "Ice cream parlor", + "de": "Eisdiele" }, "mappings": [ { "if": "name~*", "then": { - "en": "{name}" + "en": "{name}", + "de": "{name}" } } ] @@ -48,13 +52,15 @@ "presets": [ { "title": { - "en": "an ice cream parlor" + "en": "an ice cream parlor", + "de": "eine Eisdiele" }, "tags": [ "amenity=ice_cream" ], "description": { - "en": "A shop where one can buy only icecream and related items. Ice cream is normally hand-scooped." + "en": "A shop where one can buy only icecream and related items. Ice cream is normally hand-scooped.", + "de": "Ein Geschäft, in dem man nur Eiscreme und damit verbundene Artikel kaufen kann. Normalerweise wird das Eis mit der Hand portioniert." } } ], @@ -63,7 +69,8 @@ { "question": { "en": "What is the name of this ice cream parlor?", - "nl": "Wat is de naam van dit ijssalon?" + "nl": "Wat is de naam van dit ijssalon?", + "de": "Wie heißt diese Eisdiele?" }, "id": "1", "freeform": { @@ -71,7 +78,8 @@ }, "render": { "en": "This ice cream parlor is named {name}", - "nl": "Dit ijssalon heet {name}" + "nl": "Dit ijssalon heet {name}", + "de": "Diese Eisdiele heißt {name}" } }, "opening_hours", diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index cb5da7543..72a387f9e 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -1,7 +1,7 @@ { "id": "icons", "description": { - "en": "A layer acting as library for icon-tagrenderings, especially to show as badge next to a POI", + "en": "A layer acting as library for icon-tagrenderings, especially to show as badge next to a POI or as icon next to the title", "de": "Eine Ebene, die als Bibliothek für Symbol-Tag-Renderings dient, insbesondere um als Abzeichen neben einem POI angezeigt zu werden", "ca": "Una capa que actua com a biblioteca per a les icones d'etiquetes, especialment per mostrar-se com a insígnia al costat d'un PDI", "cs": "Vrstva sloužící jako knihovna pro ikony-značky, zejména pro zobrazení jako odznak vedle bodu zájmu" @@ -140,6 +140,15 @@ "render": "{share_link()}", "metacondition": "_supports_sharing=yes" }, + { + "id": "favourite_title_icon", + "labels": [ + "defaults" + ], + "render": { + "*":"{favourite_icon()}" + } + }, { "id": "osmlink", "labels": [ @@ -193,6 +202,14 @@ "class": "w-20 mx-1 flex items-center" }, "render": "{rating()}" + }, + { + "id": "favourite_icon", + "description": "Only for rendering", + "condition": "_favourite=yes", + "icon": "circle:white;heart:red", + "metacondition": "__showTimeSensitiveIcons!=no" + } ] } diff --git a/assets/layers/note/note.json b/assets/layers/note/note.json index db0771c2a..ff548401f 100644 --- a/assets/layers/note/note.json +++ b/assets/layers/note/note.json @@ -127,7 +127,7 @@ "en": "Report {_first_user} for spam or inappropriate messages", "nl": "{_first_user} melden voor spam of ongepaste opmerkingen", "de": "", - "es": "Reportar {_first_user}", + "es": "Reportar {_first_user} por spam o mensajes inapropiados", "ca": "Reporta {_first_user} per spam o missatges inapropiats", "cs": "Nahlásit uživateli {_first_user} spam nebo nevhodné zprávy" }, diff --git a/assets/layers/playground/playground.json b/assets/layers/playground/playground.json index c29fcdee5..3372d6a05 100644 --- a/assets/layers/playground/playground.json +++ b/assets/layers/playground/playground.json @@ -207,7 +207,7 @@ "ru": "Поверхность - брусчатка", "de": "Der Bodenbelag ist aus Pflastersteinen", "fr": "La surface est en pavés", - "es": "La superficie es adoquines", + "es": "La superficie es de adoquines", "ca": "La superfície són llambordes", "cs": "Povrch je dlažební kostky" } diff --git a/assets/layers/questions/questions.json b/assets/layers/questions/questions.json index 63c5c66ea..0618c5459 100644 --- a/assets/layers/questions/questions.json +++ b/assets/layers/questions/questions.json @@ -2564,31 +2564,36 @@ "diets" ], "question": { - "en": "Does this place offer a vegan option?" + "en": "Does this place offer a vegan option?", + "de": "Bietet dieser Ort eine vegane Option an?" }, "mappings": [ { "if": "diet:vegan=only", "then": { - "en": "This place only sells vegan products" + "en": "This place only sells vegan products", + "de": "Dieser Ort verkauft nur vegane Produkte" } }, { "if": "diet:vegan=yes", "then": { - "en": "This shop has a big vegan offering" + "en": "This shop has a big vegan offering", + "de": "Dieser Laden hat ein großes veganes Angebot" } }, { "if": "diet:vegan=limited", "then": { - "en": "This shop has a limited vegan offering" + "en": "This shop has a limited vegan offering", + "de": "Dieser Laden hat ein begrenztes veganes Angebot" } }, { "if": "diet:vegan=no", "then": { - "en": "This shop has no vegan offering" + "en": "This shop has no vegan offering", + "de": "Dieser Laden bietet keine veganen Produkte an" } } ] diff --git a/assets/layers/recycling/recycling.json b/assets/layers/recycling/recycling.json index 52dd111c7..2d359d3a6 100644 --- a/assets/layers/recycling/recycling.json +++ b/assets/layers/recycling/recycling.json @@ -1134,7 +1134,7 @@ "en": "Shoes can be recycled here", "nl": "Schoenen kunnen hier gerecycled worden", "de": "Schuhe können hier recycelt werden", - "es": "Aquí se pueden reciclar zapatos", + "es": "El calzado se puede reciclar aquí", "it": "Scarpe", "ca": "Aquí es poden reciclar sabates", "fr": "Les chaussures peuvent être recyclées ici", diff --git a/assets/layers/route_marker/route_marker.json b/assets/layers/route_marker/route_marker.json index 379c9b310..f47c22eba 100644 --- a/assets/layers/route_marker/route_marker.json +++ b/assets/layers/route_marker/route_marker.json @@ -1,10 +1,12 @@ { "id": "route_marker", "name": { - "en": "Route markers" + "en": "Route markers", + "de": "Routenmarkierungen" }, "description": { - "en": "Route markers are small markers often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route." + "en": "Route markers are small markers often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route.", + "de": "Routenmarkierungen sind kleine Markierungen, die häufig entlang offizieller Wander-/Rad-/Reit-/Skirouten zu finden sind, um die Richtung der Route anzuzeigen." }, "source": { "osmTags": "information=route_marker" @@ -12,7 +14,8 @@ "minzoom": 14, "title": { "render": { - "en": "Route marker" + "en": "Route marker", + "de": "Routenmarker" } }, "pointRendering": [ @@ -31,14 +34,16 @@ "presets": [ { "title": { - "en": "a route marker" + "en": "a route marker", + "de": "ein Routenmarker" }, "tags": [ "tourism=information", "information=route_marker" ], "description": { - "en": "A route marker is a small marker often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route." + "en": "A route marker is a small marker often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route.", + "de": "Ein Routenmarker ist ein kleiner Marker, der oft entlang offizieller Wander-/Fahrrad-/Reit-/Skirouten zu finden ist, um die Richtung der Route anzuzeigen." }, "exampleImages": [ "./assets/layers/route_marker/bicycle_route_marker.jpg", @@ -51,7 +56,8 @@ { "id": "type", "question": { - "en": "For what kind of route is this marker?" + "en": "For what kind of route is this marker?", + "de": "Für welche Art von Route ist dieser Marker?" }, "multiAnswer": true, "mappings": [ @@ -59,35 +65,40 @@ "if": "bicycle=yes", "ifnot": "biycle=", "then": { - "en": "This is a route marker for a bicycle route." + "en": "This is a route marker for a bicycle route.", + "de": "Dies ist ein Routenmarker für eine Fahrradstrecke." } }, { "if": "hiking=yes", "ifnot": "hiking=", "then": { - "en": "This is a route marker for a hiking route." + "en": "This is a route marker for a hiking route.", + "de": "Dies ist ein Routenmarker für eine Wanderroute." } }, { "if": "mtb=yes", "ifnot": "mtb=", "then": { - "en": "This is a route marker for a mountain bike route." + "en": "This is a route marker for a mountain bike route.", + "de": "Dies ist ein Routenmarker für eine Mountainbikestrecke." } }, { "if": "horse=yes", "ifnot": "horse=", "then": { - "en": "This is a route marker for a horse riding route." + "en": "This is a route marker for a horse riding route.", + "de": "Dies ist ein Routenmarker für eine Reitroute." } }, { "if": "ski=yes", "ifnot": "ski=", "then": { - "en": "This is a route marker for a ski route." + "en": "This is a route marker for a ski route.", + "de": "Dies ist ein Routenmarker für eine Skiroute." } } ] diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json index e78f1361e..f52867616 100644 --- a/assets/layers/shops/shops.json +++ b/assets/layers/shops/shops.json @@ -399,7 +399,8 @@ { "id": "key_cutter", "question": { - "en": "Does this shop offer key cutting?" + "en": "Does this shop offer key cutting?", + "de": "Bietet dieser Laden Schlüsselschneiden an?" }, "mappings": [ { @@ -408,7 +409,8 @@ "hideInAnswer": "shop!=shoe_repair", "icon": "./assets/layers/id_presets/fas-key.svg", "then": { - "en": "This shop is also specialized in key cutting" + "en": "This shop is also specialized in key cutting", + "de": "Dieser Laden ist auch auf das Schlüsselschneiden spezialisiert" }, "addExtraTags": [ "service:key_cutting=yes" @@ -418,7 +420,8 @@ "if": "service:key_cutting=yes", "icon": "./assets/layers/id_presets/fas-key.svg", "then": { - "en": "This shop offers key cutting as a service" + "en": "This shop offers key cutting as a service", + "de": "Dieser Laden bietet Schlüsselschneiden als Dienstleistung an" } }, { @@ -429,7 +432,8 @@ ] }, "then": { - "en": "This shops does not offer key cutting as a service" + "en": "This shops does not offer key cutting as a service", + "de": "Dieser Laden bietet kein Schlüsselschneiden als Dienstleistung an" } } ], diff --git a/assets/layers/slow_roads/slow_roads.json b/assets/layers/slow_roads/slow_roads.json index ccb9e7e03..f14bdc349 100644 --- a/assets/layers/slow_roads/slow_roads.json +++ b/assets/layers/slow_roads/slow_roads.json @@ -2,7 +2,8 @@ "id": "slow_roads", "name": { "en": "Paths, carfree and slow roads", - "nl": "Paadjes, trage wegen en autoluwe straten" + "nl": "Paadjes, trage wegen en autoluwe straten", + "de": "Pfade, autofreie und geschwindigkeitsreduzierte Straßen" }, "description": { "en": "All carfree roads", @@ -32,7 +33,8 @@ "title": { "render": { "en": "Slow road", - "nl": "Trage weg" + "nl": "Trage weg", + "de": "Geschwindigkeitsreduzierte Straße" }, "mappings": [ { @@ -46,35 +48,40 @@ "if": "highway=footway", "then": { "en": "Footway", - "nl": "Voetpad" + "nl": "Voetpad", + "de": "Fußweg" } }, { "if": "highway=cycleway", "then": { "en": "Cycleway", - "nl": "Fietspad" + "nl": "Fietspad", + "de": "Radweg" } }, { "if": "highway=pedestrian", "then": { "en": "Pedestrian street", - "nl": "Voetgangersstraat" + "nl": "Voetgangersstraat", + "de": "Fußgängerzone" } }, { "if": "highway=living_street", "then": { "en": "Living street", - "nl": "Woonerf" + "nl": "Woonerf", + "de": "Wohnstraße" } }, { "if": "highway=path", "then": { "en": "Small path", - "nl": "Klein pad" + "nl": "Klein pad", + "de": "Schmaler Pfad" } } ] @@ -133,7 +140,8 @@ "if": "highway=living_street", "then": { "en": "This is a living street", - "nl": "
Dit is een woonerf:
  • Voetgangers mogen hier de volledige breedte van de straat gebruiken
  • Gemotoriseerd verkeer mag maximaal 20km/h rijden
" + "nl": "
Dit is een woonerf:
  • Voetgangers mogen hier de volledige breedte van de straat gebruiken
  • Gemotoriseerd verkeer mag maximaal 20km/h rijden
", + "de": "Dies ist eine Wohnstraße" }, "icon": { "path": "./assets/layers/slow_roads/woonerf.svg", @@ -144,35 +152,40 @@ "if": "highway=pedestrian", "then": { "en": "This is a wide, carfree street", - "nl": "Dit is een brede, autovrije straat" + "nl": "Dit is een brede, autovrije straat", + "de": "Dies ist eine breite, autofreie Straße" } }, { "if": "highway=footway", "then": { "en": "This is a footway", - "nl": "Dit is een voetpaadje" + "nl": "Dit is een voetpaadje", + "de": "Dies ist ein Fußweg" } }, { "if": "highway=path", "then": { "en": "This is a small path", - "nl": "Dit is een wegeltje of bospad" + "nl": "Dit is een wegeltje of bospad", + "de": "Dies ist ein schmaler Pfad" } }, { "if": "highway=bridleway", "then": { "en": "This is a bridleway", - "nl": "Dit is een ruiterswegel" + "nl": "Dit is een ruiterswegel", + "de": "Dies ist ein Reitweg" } }, { "if": "highway=track", "then": { "en": "This is a land access road", - "nl": "Dit is een tractorspoor of weg om landbouwgrond te bereikken" + "nl": "Dit is een tractorspoor of weg om landbouwgrond te bereikken", + "de": "Dies ist eine Zufahrtsstraße" } } ] @@ -180,7 +193,8 @@ { "question": { "en": "What surface does this road have?", - "nl": "Wat is de wegverharding van dit pad?" + "nl": "Wat is de wegverharding van dit pad?", + "de": "Welche Oberfläche hat diese Straße?" }, "render": { "nl": "De ondergrond is {surface}", @@ -318,7 +332,8 @@ "id": "slow_road_is_lit", "question": { "en": "Is this road lit at night?", - "nl": "Is deze weg 's nachts verlicht?" + "nl": "Is deze weg 's nachts verlicht?", + "de": "Ist diese Straße nachts beleuchtet?" }, "mappings": [ { @@ -329,7 +344,8 @@ "if": "lit=no", "then": { "en": "Not lit", - "nl": "Niet verlicht" + "nl": "Niet verlicht", + "de": "Nicht beleuchtet" } } ] diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index 22bb4f1fb..91dc7dc9d 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -487,7 +487,7 @@ "nl": "Welke toiletten zijn dit?", "it": "Di che tipo di servizi igienici si tratta?", "ru": "Какие это туалеты?", - "es": "¿Qué tipo de baños son estos?", + "es": "¿Qué tipo de aseos son?", "da": "Hvilken slags toiletter er det?", "ca": "Quin tipus de lavabo són aquests?", "cs": "O jaký druh záchodů se jedná?" @@ -707,7 +707,7 @@ "en": "These toilets have a sink to wash your hands", "nl": "Deze toiletten hebben een lavabo waar men de handen kan wassen", "de": "Die Toilette hat ein Handwaschbecken", - "es": "Estos baños tienen una pileta para lavarse las manos", + "es": "Estos aseos tienen un lavabo para lavarse las manos", "fr": "Ces toilettes ont un lavabo pour se laver les mains", "da": "Dette toilet har en vask til at vaske dine hænder", "ca": "Aquests lavabos tenen una pica per a rentar-te les mans", @@ -720,7 +720,7 @@ "en": "These toilets don't have a sink to wash your hands", "nl": "Deze toiletten hebben geen lavabo waar men de handen kan wassen", "de": "Die Toilette hat kein Handwaschbecken", - "es": "Estos baños no tienen una pileta para lavarse las manos", + "es": "Estos aseos no tienen lavabo para lavarse las manos", "fr": "Ces toilettes n'ont pas de lavabo pour se laver les mains", "da": "Disse toiletter har ikke en vask til at vaske dine hænder", "ca": "Aquests lavabos no tenen una pica per a rentar-te les mans", diff --git a/assets/layers/trail/trail.json b/assets/layers/trail/trail.json index e6bacfdf3..f90dabfe3 100644 --- a/assets/layers/trail/trail.json +++ b/assets/layers/trail/trail.json @@ -12,7 +12,8 @@ }, "description": { "en": "Waymarked trails", - "nl": "Aangeduide wandeltochten" + "nl": "Aangeduide wandeltochten", + "de": "Markierte Wanderwege" }, "source": { "osmTags": { @@ -105,11 +106,13 @@ { "question": { "en": "What is the name of this trail?", - "nl": "Wat is de naam van deze wandeling?" + "nl": "Wat is de naam van deze wandeling?", + "de": "Wie heißt dieser Weg?" }, "render": { "en": "This trail is called {name}", - "nl": "Deze wandeling heet {name}" + "nl": "Deze wandeling heet {name}", + "de": "Dieser Weg heißt {name}" }, "freeform": { "key": "name" @@ -119,11 +122,13 @@ { "render": { "en": "This trail is maintained by {operator}", - "nl": "Beheer door {operator}" + "nl": "Beheer door {operator}", + "de": "Dieser Weg wird von {operator} gepflegt" }, "question": { "en": "Who maintains this trail?", - "nl": "Wie beheert deze wandeltocht?" + "nl": "Wie beheert deze wandeltocht?", + "de": "Wer pflegt diesen Weg?" }, "freeform": { "key": "operator" @@ -137,7 +142,8 @@ }, "then": { "en": "This trail is maintained by Natuurpunt", - "nl": "Dit gebied wordt beheerd door Natuurpunt" + "nl": "Dit gebied wordt beheerd door Natuurpunt", + "de": "Dieser Weg wird von Natuurpunt gepflegt" }, "icon": { "path": "./assets/themes/buurtnatuur/Natuurpunt.jpg", @@ -152,7 +158,8 @@ }, "then": { "en": "This trail is maintained by {operator}", - "nl": "Dit gebied wordt beheerd door {operator}" + "nl": "Dit gebied wordt beheerd door {operator}", + "de": "Dieser Weg wird von {operator} gepflegt" }, "hideInAnswer": true, "icon": { @@ -166,11 +173,13 @@ { "question": { "en": "What is the reference colour of this trail?", - "nl": "Welke kleur heeft deze wandeling?" + "nl": "Welke kleur heeft deze wandeling?", + "de": "Was ist die Referenzfarbe dieses Weges?" }, "render": { "en": "The reference colour is {colour}", - "nl": "Deze wandeling heeft kleur {colour}" + "nl": "Deze wandeling heeft kleur {colour}", + "de": "Die Referenzfarbe ist {colour}" }, "freeform": { "key": "colour", @@ -231,20 +240,23 @@ { "question": { "en": "Is this trail wheelchair accessible?", - "nl": "Is deze wandeling toegankelijk met de rolstoel?" + "nl": "Is deze wandeling toegankelijk met de rolstoel?", + "de": "Ist dieser Weg rollstuhlgerecht?" }, "mappings": [ { "then": { "en": "This trail is wheelchair-accessible", - "nl": "deze wandeltocht is toegankelijk met de rolstoel" + "nl": "deze wandeltocht is toegankelijk met de rolstoel", + "de": "Dieser Weg ist rollstuhlgerecht" }, "if": "wheelchair=yes" }, { "then": { "en": "This trail is not wheelchair accessible", - "nl": "deze wandeltocht is niet toegankelijk met de rolstoel" + "nl": "deze wandeltocht is niet toegankelijk met de rolstoel", + "de": "Dieser Weg ist nicht rollstuhlgerecht" }, "if": "wheelchair=no" } @@ -254,20 +266,23 @@ { "question": { "en": "Is this trail accessible with a pushchair?", - "nl": "Is deze wandeltocht toegankelijk met de buggy?" + "nl": "Is deze wandeltocht toegankelijk met de buggy?", + "de": "Ist dieser Weg mit einem Kinderwagen zugänglich?" }, "mappings": [ { "then": { "en": "This trail is accessible with a pushchair", - "nl": "deze wandeltocht is toegankelijk met de buggy" + "nl": "deze wandeltocht is toegankelijk met de buggy", + "de": "Dieser Weg ist mit einem Kinderwagen zugänglich" }, "if": "pushchair=yes" }, { "then": { "en": "This trail is not accessible with a pushchair", - "nl": "deze wandeltocht is niet toegankelijk met de buggy" + "nl": "deze wandeltocht is niet toegankelijk met de buggy", + "de": "Dieser Weg ist nicht mit einem Kinderwagen zugänglich" }, "if": "pushchair=no" } diff --git a/assets/layers/tree_node/tree_node.json b/assets/layers/tree_node/tree_node.json index 85e6bbabd..c6a7c66cf 100644 --- a/assets/layers/tree_node/tree_node.json +++ b/assets/layers/tree_node/tree_node.json @@ -319,7 +319,7 @@ "pt_BR": "Qual a altura dessa árvore?", "ca": "Quina és l'alçada d'aquest arbre?", "cs": "Jaká je výška tohoto stromu?", - "es": "¿Cuál es la altura de este árbol?" + "es": "¿Qué altura tiene este árbol?" }, "freeform": { "key": "height", @@ -440,7 +440,7 @@ "en": "The tree is in a residential garden.", "it": "L’albero è un giardino residenziale.", "fr": "Cet arbre est dans une jardin de résidence.", - "es": "El árbol está en un jardín privado o residencial.", + "es": "El árbol está en un jardín de una vivienda.", "de": "Der Baum steht in einem Wohngarten.", "da": "Træet står i en villahave.", "ca": "L'arbre està en un jardí residencial.", @@ -478,7 +478,7 @@ "en": "The tree is in an urban area.", "it": "L’albero si trova in un’area urbana.", "fr": "L'arbre est dans une zone urbaine.", - "es": "El árbol está en un zona urbana.", + "es": "El árbol está en una zona urbana.", "de": "Der Baum steht in einem städtischen Gebiet.", "da": "Træet står i et byområde.", "ca": "L'arbre està en una àrea urbana.", diff --git a/assets/themes/cyclenodes/cyclenodes.json b/assets/themes/cyclenodes/cyclenodes.json index b022ba6ea..2bb5eb2bb 100644 --- a/assets/themes/cyclenodes/cyclenodes.json +++ b/assets/themes/cyclenodes/cyclenodes.json @@ -329,7 +329,8 @@ "bicycle=yes" ], "title": { - "en": "a route marker for a node to node link" + "en": "a route marker for a node to node link", + "de": "Eine Routenmarkierung für eine Verbindung von Knoten zu Knoten" }, "=exampleImages": [ "./assets/layers/route_marker/bicycle_route_marker.jpg" diff --git a/assets/themes/icecream/icecream.json b/assets/themes/icecream/icecream.json index 3d7e00a1b..e9c135f3e 100644 --- a/assets/themes/icecream/icecream.json +++ b/assets/themes/icecream/icecream.json @@ -1,10 +1,12 @@ { "id": "icecream", "title": { - "en": "Icecream" + "en": "Icecream", + "de": "Eiscreme" }, "description": { - "en": "A map showing ice cream parlors and ice cream vending machines" + "en": "A map showing ice cream parlors and ice cream vending machines", + "de": "Eine Karte, die Eisdielen und Eisautomaten zeigt" }, "icon": "./assets/layers/ice_cream/ice_cream.svg", "layers": [ diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json index 9b37d1f43..f4986e0aa 100644 --- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json +++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json @@ -1,13 +1,33 @@ { "id": "mapcomplete-changes", "title": { - "en": "Changes made with MapComplete" + "en": "Changes made with MapComplete", + "ca": "Canvis fets amb MapComplete", + "cs": "Změny provedené pomocí MapComplete", + "de": "Mit MapComplete erstellte Änderungen", + "es": "Cambios realizados con MapComplete", + "fr": "Changements faits avec MapComplete", + "nl": "Wijzigingen gemaakt met MapComplete", + "pl": "Zmiany wprowadzone za pomocą MapComplete" }, "shortDescription": { - "en": "Shows changes made by MapComplete" + "en": "Show changes made with MapComplete", + "ca": "Mostra els canvis fets amb MapComplete", + "cs": "Zobrazení změn provedených pomocí nástroje MapComplete", + "de": "Mit MapComplete erstellte Änderungen anzeigen", + "es": "Mostrar cambios realizados con MapComplete", + "nl": "Toon wijzigingen gemaakt met MapComplete", + "pl": "Pokaż zmiany wprowadzone za pomocą MapComplete" }, "description": { - "en": "This maps shows all the changes made with MapComplete" + "en": "This maps shows all the changes made with MapComplete", + "ca": "Aquest mapa mostra tots els canvis fets amb MapComplete", + "cs": "Tato mapa zobrazuje všechny změny provedené pomocí MapComplete", + "de": "Diese Karte zeigt alle mit MapComplete vorgenommenen Änderungen", + "es": "Este mapa muestra todos los cambios realizados con MapComplete", + "fr": "Cette carte montre tous les changements faits avec MapComplete", + "nl": "Deze kaart toont alle wijzigingen die met MapComplete gemaakt werden", + "pl": "Ta mapa pokazuje wszystkie zmiany wprowadzone za pomocą MapComplete" }, "icon": "./assets/svg/logo.svg", "hideFromOverview": true, @@ -20,7 +40,13 @@ { "id": "mapcomplete-changes", "name": { - "en": "Changeset centers" + "en": "Changeset centers", + "ca": "Centre del conjunt de canvis", + "cs": "Centrum změn", + "de": "Zentrum der Änderungssätze", + "es": "Centro del conjunto de cambios", + "nl": "Centerpunt van changeset", + "pl": "Centra zmian" }, "minzoom": 0, "source": { @@ -31,41 +57,85 @@ }, "title": { "render": { - "en": "Changeset for {theme}" + "en": "Changeset for {theme}", + "ca": "Conjunt de canvis per a {theme}", + "cs": "Změna pro {theme}", + "de": "Änderungssatz für {theme}", + "es": "Conjunto de cambios para {theme}", + "fr": "Groupe de modifications pour {theme}", + "pl": "Zestaw zmian dla {theme}" } }, "description": { - "en": "Shows all MapComplete changes" + "en": "Show all MapComplete changes", + "ca": "Mostra tots els canvis de MapComplete", + "cs": "Zobrazit všechny změny MapComplete", + "de": "Alle MapComplete-Änderungen anzeigen", + "es": "Mostrar todos los cambios de MapComplete", + "nl": "Toon alle MapComplete wijzigingen", + "pl": "Wyświetl wszystkie zmiany MapComplete" }, "tagRenderings": [ { "id": "show_changeset_id", "render": { - "en": "Changeset
{id}" + "en": "Changeset {id}", + "ca": "Conjunt de canvi {id}", + "cs": "Změny {id}", + "de": "Änderungssatz {id}", + "es": "Conjunto de cambios {id}", + "fr": "Groupe de modifications {id}", + "pl": "Zestaw zmian {id}" } }, { "id": "contributor", "question": { - "en": "What contributor did make this change?" + "en": "Which contributor made this change?", + "ca": "Quin col·laborador va fer aquest canvi?", + "cs": "Který přispěvatel tuto změnu provedl?", + "de": "Wer hat diese Änderung vorgenommen?", + "es": "¿Qué contribuidor hizo este cambio?", + "fr": "Quel contributeur a fait cette modification ?", + "nl": "Welke bijdrager maakte deze wijziging?", + "pl": "Który współautor dokonał tej zmiany?" }, "freeform": { "key": "user" }, "render": { - "en": "Change made by {user}" + "en": "Change made by {user}", + "ca": "Canvi fet per {user}", + "cs": "Změna provedená {user}", + "de": "Änderung von {user}", + "es": "Cambio realizado por {user}", + "fr": "Modification faite par {user}", + "nl": "Wijziging gemaakt door {user}", + "pl": "Zmiana dokonana przez {user}" } }, { "id": "theme-id", "question": { - "en": "What theme was used to make this change?" + "en": "What theme was used to make this change?", + "ca": "Quin tema es va utilitzar per fer aquest canvi?", + "cs": "Jaké téma bylo použito k provedení této změny?", + "de": "Welches Thema wurde für diese Änderung verwendet?", + "es": "¿Qué tema se utilizó para realizar este cambio?", + "fr": "Quel thème a été utilisé pour faire cette modification ?", + "pl": "Jakiego tematu użyto do wprowadzenia tej zmiany?" }, "freeform": { "key": "theme" }, "render": { - "en": "Change with theme {theme}" + "en": "Change with theme {theme}", + "ca": "Canvi amb el tema {theme}", + "cs": "Změna s motivem {theme}", + "de": "Geändert mit Thema {theme}", + "es": "Cambio con tema {theme}", + "fr": "Modifié avec le thème {theme}", + "pl": "Zmiana za pomocą motywu {theme}" } }, { @@ -74,19 +144,45 @@ "key": "locale" }, "question": { - "en": "What locale (language) was this change made in?" + "en": "What locale (language) was this change made in?", + "ca": "Amb quina configuració regional (idioma) s'ha fet aquest canvi?", + "cs": "V jakém národním prostředí (jazyce) byla tato změna provedena?", + "de": "In welcher Benutzersprache wurde diese Änderung vorgenommen?", + "es": "¿En qué configuración regional (idioma) se realizó este cambio?", + "fr": "En quelle langue est-ce que ce changement a été fait ?", + "nl": "In welke locale (taal) werd deze wijziging gemaakt?", + "pl": "W jakim języku wprowadzono tę zmianę?" }, "render": { - "en": "User locale is {locale}" + "en": "User locale is {locale}", + "ca": "La configuració regional de l'usuari és {locale}", + "cs": "Uživatelské prostředí je {locale}", + "de": "Benutzersprache {locale}", + "es": "La configuración regional del usuario es {locale}", + "nl": "De gebruikerstaal is {locale}", + "pl": "Ustawienia regionalne użytkownika to {locale}" } }, { "id": "host", "render": { - "en": "Change with with {host}" + "en": "Change made with {host}", + "ca": "Canviat fet amb {host}", + "cs": "Změna provedená pomocí {host}", + "de": "Geändert über {host}", + "es": "Cambio realizado con {host}", + "fr": "Modification faite avec {host}", + "nl": "Wijziging gemaakt met {host}", + "pl": "Zmiana dokonana w {host}" }, "question": { - "en": "What host (website) was this change made with?" + "en": "What host (website) was this change made with?", + "ca": "Amb quin amfitrió (lloc web) es va fer aquest canvi?", + "cs": "U jakého hostitele (webové stránky) byla tato změna provedena?", + "de": "Über welchen Host (Webseite) wurde diese Änderung vorgenommen?", + "es": "¿Con qué host (página web) se realizó este cambio?", + "nl": "Met welke host (website) werd deze wijziging gemaakt?", + "pl": "Na jakim hoście (stronie internetowej) dokonano tej zmiany?" }, "freeform": { "key": "host" @@ -107,10 +203,22 @@ { "id": "version", "question": { - "en": "What version of MapComplete was used to make this change?" + "en": "What version of MapComplete was used to make this change?", + "ca": "Quina versió de MapComplete es va utilitzar per fer aquest canvi?", + "cs": "Jaká verze aplikace MapComplete byla použita k provedení této změny?", + "de": "Mit welcher Version von MapComplete wurde diese Änderung gemacht?", + "es": "¿Qué versión de MapComplete se usó para realizar este cambio?", + "fr": "Quelle version de MapComplete a été utilisée pour faire cette modification ?", + "pl": "Która wersja MapComplete została wykorzystana, aby zrobić tę zmianę?" }, "render": { - "en": "Made with {editor}" + "en": "Made with {editor}", + "ca": "Fet amb {editor}", + "cs": "Vyrobeno pomocí {editor}", + "de": "Erstellt mit {editor}", + "es": "Realizado con {editor}", + "fr": "Fait avec {editor}", + "pl": "Zrobione za pomocą {editor}" }, "freeform": { "key": "editor" @@ -456,7 +564,13 @@ } ], "question": { - "en": "Themename contains {search}" + "en": "Theme name contains {search}", + "ca": "El nom del tema conté {search}", + "cs": "Název motivu obsahuje {search}", + "de": "Themenname enthält {search}", + "es": "El nombre del tema contiene {search}", + "nl": "Themenaam bevat {search}", + "pl": "Nazwa tematu zawiera {search}" } } ] @@ -472,7 +586,13 @@ } ], "question": { - "en": "Made by contributor {search}" + "en": "Made by contributor {search}", + "ca": "Fet pel col·laborador {search}", + "cs": "Vytvořil přispěvatel {search}", + "de": "Erstellt von {search}", + "es": "Hecho por el colaborador {search}", + "nl": "Gemaakt door bijdrager {search}", + "pl": "Wykonane przez współautora {search}" } } ] @@ -488,7 +608,13 @@ } ], "question": { - "en": "Not made by contributor {search}" + "en": "Not made by contributor {search}", + "ca": "No fet pel col·laborador {search}", + "cs": "Není vytvořeno přispěvatelem {search}", + "de": "Nicht erstellt von {search}", + "es": "No hecho por el colaborador {search}", + "nl": "Niet gemaakt door bijdrager {search}", + "pl": "Nie wykonane przez współautora {search}" } } ] @@ -505,7 +631,13 @@ } ], "question": { - "en": "Made before {search}" + "en": "Made before {search}", + "ca": "Fet abans de {search}", + "cs": "Vytvořeno před {search}", + "de": "Erstellt vor {search}", + "es": "Hecho antes de {search}", + "nl": "Gemaakt voor {search}", + "pl": "Stworzone przed {search}" } } ] @@ -522,7 +654,13 @@ } ], "question": { - "en": "Made after {search}" + "en": "Made after {search}", + "ca": "Fet després de {search}", + "cs": "Vytvořeno po {search}", + "de": "Erstellt nach {search}", + "es": "Hecho después de {search}", + "nl": "Gemaakt na {search}", + "pl": "Stworzone po {search}" } } ] @@ -538,7 +676,14 @@ } ], "question": { - "en": "User language (iso-code) {search}" + "en": "User language (iso-code) {search}", + "ca": "Idioma de l'usuari (codi iso) {search}", + "cs": "Jazyk uživatele (iso-kód) {search}", + "de": "Benutzersprache (ISO-Code) {search}", + "es": "Use idioma (ISO-code) {search}", + "fr": "Langage utilisateur (code-ISO) {search}", + "nl": "De taal van de bijdrager is {search}", + "pl": "Język użytkownika (kod iso) {search}" } } ] @@ -554,7 +699,13 @@ } ], "question": { - "en": "Made with host {search}" + "en": "Made with host {search}", + "ca": "Fet amb l'amfitrió {search}", + "cs": "Vytvořeno pomocí hostitele {search}", + "de": "Erstellt mit Host {search}", + "es": "Hecho con el host {search}", + "nl": "Gemaakt met host {search}", + "pl": "Wykonane z hostem {search}" } } ] @@ -565,7 +716,14 @@ { "osmTags": "add-image>0", "question": { - "en": "Changeset added at least one image" + "en": "Changeset added at least one image", + "ca": "El conjunt de canvis ha afegit almenys una imatge", + "cs": "Sada změn přidala alespoň jeden obrázek", + "de": "Im Änderungssatz wurde mindestens ein Bild hinzugefügt", + "es": "El conjunto de cambios ha añadido al menos una imagen", + "fr": "Le groupe de modifications a ajouté au moins une image", + "nl": "Changeset bevat minstens één afbeelding", + "pl": "Zestaw zmian dodał co najmniej jedno zdjęcie" } } ] @@ -580,7 +738,13 @@ { "id": "link_to_more", "render": { - "en": "More statistics can be found here" + "en": "More statistics can be found here", + "ca": "Es pot trobar més estadística aquí", + "cs": "Další statistiky najdete here", + "de": "Mehr Statistiken gibt es hier", + "es": "Puede encontrar más estadísticas aquí", + "fr": "D'autres statistiques sont disponibles ici", + "pl": "Więcej statystyk można znaleźć tutaj" } }, { diff --git a/assets/themes/walkingnodes/walkingnodes.json b/assets/themes/walkingnodes/walkingnodes.json index d0ec2c816..3d08f5019 100644 --- a/assets/themes/walkingnodes/walkingnodes.json +++ b/assets/themes/walkingnodes/walkingnodes.json @@ -2,11 +2,13 @@ "id": "walkingnodes", "title": { "en": "Walking Node Networks", - "nl": "Wandelknooppuntnetwerken" + "nl": "Wandelknooppuntnetwerken", + "de": "Netzwerke von Wanderknoten" }, "description": { "en": "This map shows walking node networks and allows you to add new nodes easily", - "nl": "Deze kaart toont wandelknooppunten en laat je toe om eenvoudigweg nieuwe knooppunten toe te voegen" + "nl": "Deze kaart toont wandelknooppunten en laat je toe om eenvoudigweg nieuwe knooppunten toe te voegen", + "de": "Diese Karte zeigt Wandernetzwerke und ermöglicht es Ihnen, einfach neue Knoten hinzuzufügen" }, "icon": "./assets/themes/walkingnodes/logo.svg", "startZoom": 11, @@ -149,7 +151,8 @@ "title": { "render": { "en": "Walking node {rwn_ref}", - "nl": "Wandelknooppunt {rwn_ref}" + "nl": "Wandelknooppunt {rwn_ref}", + "de": "Wanderknoten {rwn_ref}" } }, "tagRenderings": [ @@ -157,19 +160,22 @@ "id": "node-rwn_ref", "question": { "en": "What is the reference number of this walking node?", - "nl": "Wat is het referentienummer van dit wandelknooppunt?" + "nl": "Wat is het referentienummer van dit wandelknooppunt?", + "de": "Was ist die Referenznummer dieses Wanderknotens?" }, "freeform": { "key": "rwn_ref", "type": "int", "placeholder": { "en": "e.g. 1", - "nl": "bijv. 1" + "nl": "bijv. 1", + "de": "z.B. 1" } }, "render": { "en": "This walking node has reference number {rwn_ref}", - "nl": "Dit wandelknooppunt heeft referentienummer {rwn_ref}" + "nl": "Dit wandelknooppunt heeft referentienummer {rwn_ref}", + "de": "Dieser Wanderknoten hat die Referenznummer {rwn_ref}" } }, { @@ -177,29 +183,34 @@ "override": { "question": { "en": "When was this walking node last surveyed?", - "nl": "Wanneer is dit wandelknooppunt het laatst gesurveyed?" + "nl": "Wanneer is dit wandelknooppunt het laatst gesurveyed?", + "de": "Wann wurde dieser Wanderknoten zuletzt überprüft?" }, "render": { "en": "This walking node was last surveyed on {survey:date}", - "nl": "Dit wandelknooppunt werd het laatst gesurveyed op {survey:date}" + "nl": "Dit wandelknooppunt werd het laatst gesurveyed op {survey:date}", + "de": "Dieser Wanderknoten wurde zuletzt am {survey:date} überprüft" } } }, { "question": { "en": "How many other walking nodes does this node link to?", - "nl": "Met hoeveel andere wandelknooppunten heeft dit knooppunt een verbinding?" + "nl": "Met hoeveel andere wandelknooppunten heeft dit knooppunt een verbinding?", + "de": "Mit wie vielen anderen Wanderknoten ist dieser Knoten verbunden?" }, "render": { "en": "This node links to {expected_rwn_route_relations} other walking nodes.", - "nl": "Dit knooppunt verbindt met {expected_rwn_route_relations} andere wandelknooppunten." + "nl": "Dit knooppunt verbindt met {expected_rwn_route_relations} andere wandelknooppunten.", + "de": "Dieser Knoten ist mit {expected_rwn_route_relations} anderen Wanderknoten verbunden." }, "freeform": { "key": "expected_rwn_route_relations", "type": "int", "placeholder": { "en": "e.g. 3", - "nl": "bijv. 3" + "nl": "bijv. 3", + "de": "z.B. 3" } }, "id": "node-expected_rwn_route_relations" @@ -214,7 +225,8 @@ ], "title": { "en": "a walking node", - "nl": "een wandelknooppunt" + "nl": "een wandelknooppunt", + "de": "ein Wanderknoten" }, "snapToLayer": [ "cycleways_and_roads" @@ -246,11 +258,13 @@ } ], "name": { - "en": "Hiking guideposts" + "en": "Hiking guideposts", + "de": "Wanderwegweiser" }, "title": { "render": { - "en": "Hiking guidepost" + "en": "Hiking guidepost", + "de": "Wanderwegweiser" } } }, @@ -280,7 +294,8 @@ "hiking=yes" ], "title": { - "en": "a route marker for a node to node link" + "en": "a route marker for a node to node link", + "de": "Eine Routenmarkierung für eine Verbindung von Knoten zu Knoten" }, "=exampleImages": [ "./assets/layers/route_marker/walking_route_marker.jpg" diff --git a/langs/en.json b/langs/en.json index 51286265d..d7a2241cb 100644 --- a/langs/en.json +++ b/langs/en.json @@ -50,6 +50,15 @@ "panelIntro": "

Your personal theme

Activate your favourite layers from all the official themes", "reload": "Reload the data" }, + "favouritePoi": { + "button": { + "isFavourite": "This location is currently marked as favourite and will show up on all thematic maps of MapComplete you visit.", + "markAsFavouriteTitle": "Mark this location as favourite location", + "markDescription": "Add this location to a personal list of your favourites", + "unmark": "Remove from your personal list of favourites", + "unmarkNotDeleted": "This point will not be deleted and still be visible on the appropriate map for you and others" + } + }, "flyer": { "aerial": "This map uses a different background, namely aerial imagery by Agentschap Informatie Vlaanderen", "callToAction": "Test it on mapcomplete.org", diff --git a/langs/layers/de.json b/langs/layers/de.json index 765464ff4..4067c6339 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -35,16 +35,6 @@ "1": { "title": "eine freistehende Posterbox" }, - "10": { - "description": "Verwendet für Werbeschilder, Leuchtreklamen, Logos und institutionelle Eingangsschilder", - "title": "ein Schild" - }, - "11": { - "title": "eine Skulptur" - }, - "12": { - "title": "eine Wandmalerei" - }, "2": { "title": "eine wandmontierte Posterbox" }, @@ -71,6 +61,16 @@ }, "9": { "title": "ein Totem" + }, + "10": { + "description": "Verwendet für Werbeschilder, Leuchtreklamen, Logos und institutionelle Eingangsschilder", + "title": "ein Schild" + }, + "11": { + "title": "eine Skulptur" + }, + "12": { + "title": "eine Wandmalerei" } }, "tagRenderings": { @@ -165,9 +165,6 @@ "1": { "then": "Dies ist ein Brett" }, - "10": { - "then": "Dies ist eine Wandmalerei" - }, "2": { "then": "Dies ist eine Litfaßsäule" }, @@ -191,6 +188,9 @@ }, "9": { "then": "Dies ist ein Totem" + }, + "10": { + "then": "Dies ist eine Wandmalerei" } }, "question": "Welche Art von Werbung ist das?", @@ -205,9 +205,6 @@ "1": { "then": "Brett" }, - "10": { - "then": "Wandmalerei" - }, "2": { "then": "Posterbox" }, @@ -231,6 +228,9 @@ }, "9": { "then": "Totem" + }, + "10": { + "then": "Wandmalerei" } } } @@ -353,15 +353,6 @@ "1": { "then": "Wandbild" }, - "10": { - "then": "Azulejo (spanische dekorative Fliesenarbeit)" - }, - "11": { - "then": "Fliesenarbeit" - }, - "12": { - "then": "Holzschnitzerei" - }, "2": { "then": "Malerei" }, @@ -385,6 +376,15 @@ }, "9": { "then": "Relief" + }, + "10": { + "then": "Azulejo (spanische dekorative Fliesenarbeit)" + }, + "11": { + "then": "Fliesenarbeit" + }, + "12": { + "then": "Holzschnitzerei" } }, "question": "Um welche Art Kunstwerk handelt es sich?", @@ -1942,27 +1942,6 @@ "1": { "question": "Verfügt über einen
Schuko-Stecker ohne Erdungsstift (CEE7/4 Typ F)
" }, - "10": { - "question": "Hat einen
Typ 2 (Mennekes)
Anschluss mit Kabel" - }, - "11": { - "question": "Hat einen
Tesla Supercharger CCS (Typ 2 CSS vonTesla)
Anschluss" - }, - "12": { - "question": "Hat einen
Tesla Supercharger (Destination)
Anschluss" - }, - "13": { - "question": "Hat einen
Tesla Supercharger (Destination) (Typ 2 von Tesla)
Anschluss mit Kabel" - }, - "14": { - "question": "Hat einen
USB-Anschluss zum Aufladen von Telefonen und kleinen Elektrogeräten
" - }, - "15": { - "question": "Hat einen
Bosch Active Connect Anschluss mit 3 Pins
und Kabel" - }, - "16": { - "question": "Hat einen
Bosch Active Connect Anschluss mit 5 Pins
und Kabel" - }, "2": { "question": "Verfügt über einen
europäischen Netzstecker mit Erdungsstift (CEE7/4 Typ E)
Anschluss" }, @@ -1986,6 +1965,27 @@ }, "9": { "question": "Hat einen
Typ 2 CCS (Mennekes)
Anschluss" + }, + "10": { + "question": "Hat einen
Typ 2 (Mennekes)
Anschluss mit Kabel" + }, + "11": { + "question": "Hat einen
Tesla Supercharger CCS (Typ 2 CSS vonTesla)
Anschluss" + }, + "12": { + "question": "Hat einen
Tesla Supercharger (Destination)
Anschluss" + }, + "13": { + "question": "Hat einen
Tesla Supercharger (Destination) (Typ 2 von Tesla)
Anschluss mit Kabel" + }, + "14": { + "question": "Hat einen
USB-Anschluss zum Aufladen von Telefonen und kleinen Elektrogeräten
" + }, + "15": { + "question": "Hat einen
Bosch Active Connect Anschluss mit 3 Pins
und Kabel" + }, + "16": { + "question": "Hat einen
Bosch Active Connect Anschluss mit 5 Pins
und Kabel" } } } @@ -2041,6 +2041,30 @@ "1": { "then": "Schuko-Stecker ohne Erdungsstift (CEE7/4 Typ F)" }, + "2": { + "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)" + }, + "3": { + "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)" + }, + "4": { + "then": "Chademo-Anschluss" + }, + "5": { + "then": "Chademo-Anschluss" + }, + "6": { + "then": "Typ 1 mit Kabel (J1772)" + }, + "7": { + "then": "Typ 1 mit Kabel (J1772)" + }, + "8": { + "then": "Typ 1 ohne Kabel (J1772)" + }, + "9": { + "then": " Typ 1 ohne Kabel (J1772)" + }, "10": { "then": "Typ 1 CCS (Typ 1 Combo)" }, @@ -2071,9 +2095,6 @@ "19": { "then": "Typ 2 mit Kabel (mennekes)" }, - "2": { - "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)" - }, "20": { "then": "Tesla Supercharger CCS (Typ 2 CSS von Tesla)" }, @@ -2104,32 +2125,11 @@ "29": { "then": " Bosch Active Connect mit 3 Pins und Kabel" }, - "3": { - "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)" - }, "30": { "then": "Bosch Active Connect mit 5 Pins und Kabel" }, "31": { "then": " Bosch Active Connect mit 5 Pins und Kabel" - }, - "4": { - "then": "Chademo-Anschluss" - }, - "5": { - "then": "Chademo-Anschluss" - }, - "6": { - "then": "Typ 1 mit Kabel (J1772)" - }, - "7": { - "then": "Typ 1 mit Kabel (J1772)" - }, - "8": { - "then": "Typ 1 ohne Kabel (J1772)" - }, - "9": { - "then": " Typ 1 ohne Kabel (J1772)" } }, "question": "Welche Ladeanschlüsse gibt es hier?" @@ -3667,15 +3667,6 @@ "1": { "then": "Dieser Radweg hat einen festen Belag" }, - "10": { - "then": "Dieser Radweg besteht aus feinem Schotter" - }, - "11": { - "then": "Der Radweg ist aus Kies" - }, - "12": { - "then": "Dieser Radweg besteht aus Rohboden" - }, "2": { "then": "Der Radweg ist aus Asphalt" }, @@ -3699,6 +3690,15 @@ }, "9": { "then": "Der Radweg ist aus Schotter" + }, + "10": { + "then": "Dieser Radweg besteht aus feinem Schotter" + }, + "11": { + "then": "Der Radweg ist aus Kies" + }, + "12": { + "then": "Dieser Radweg besteht aus Rohboden" } }, "question": "Was ist der Belag dieses Radwegs?", @@ -3747,15 +3747,6 @@ "1": { "then": "Dieser Radweg hat einen festen Belag" }, - "10": { - "then": "Dieser Radweg besteht aus feinem Schotter" - }, - "11": { - "then": "Der Radweg ist aus Kies" - }, - "12": { - "then": "Dieser Radweg besteht aus Rohboden" - }, "2": { "then": "Der Radweg ist aus Asphalt" }, @@ -3779,6 +3770,15 @@ }, "9": { "then": "Der Radweg ist aus Schotter" + }, + "10": { + "then": "Dieser Radweg besteht aus feinem Schotter" + }, + "11": { + "then": "Der Radweg ist aus Kies" + }, + "12": { + "then": "Dieser Radweg besteht aus Rohboden" } }, "question": "Was ist der Belag dieser Straße?", @@ -4678,54 +4678,6 @@ } } }, - "10": { - "options": { - "0": { - "question": "Keine Bevorzugung von Hunden" - }, - "1": { - "question": "Hunde erlaubt" - }, - "2": { - "question": "Keine Hunde erlaubt" - } - } - }, - "11": { - "options": { - "0": { - "question": "Internetzugang vorhanden" - } - } - }, - "12": { - "options": { - "0": { - "question": "Stromanschluss vorhanden" - } - } - }, - "13": { - "options": { - "0": { - "question": "Hat zuckerfreie Angebote" - } - } - }, - "14": { - "options": { - "0": { - "question": "Hat glutenfreie Angebote" - } - } - }, - "15": { - "options": { - "0": { - "question": "Hat laktosefreie Angebote" - } - } - }, "2": { "options": { "0": { @@ -4796,6 +4748,54 @@ "question": "Nutzung kostenlos" } } + }, + "10": { + "options": { + "0": { + "question": "Keine Bevorzugung von Hunden" + }, + "1": { + "question": "Hunde erlaubt" + }, + "2": { + "question": "Keine Hunde erlaubt" + } + } + }, + "11": { + "options": { + "0": { + "question": "Internetzugang vorhanden" + } + } + }, + "12": { + "options": { + "0": { + "question": "Stromanschluss vorhanden" + } + } + }, + "13": { + "options": { + "0": { + "question": "Hat zuckerfreie Angebote" + } + } + }, + "14": { + "options": { + "0": { + "question": "Hat glutenfreie Angebote" + } + } + }, + "15": { + "options": { + "0": { + "question": "Hat laktosefreie Angebote" + } + } } } }, @@ -4915,6 +4915,30 @@ "1": { "then": "Die Fitness-Station hat ein Schild mit Anweisungen für eine bestimmte Übung." }, + "2": { + "then": "Die Fitness-Station hat eine Einrichtung für Sit-ups." + }, + "3": { + "then": "Die Fitness-Station hat eine Vorrichtung für Liegestütze. In der Regel eine oder mehrere niedrige Reckstangen." + }, + "4": { + "then": "Die Fitness-Station hat Stangen zum Dehnen." + }, + "5": { + "then": "Die Fitness-Station hat eine Vorrichtung für Rückenstrecker (Hyperextensions)." + }, + "6": { + "then": "Die Fitness-Station hat Ringe für Gymnastikübungen." + }, + "7": { + "then": "Die Fitness-Station hat eine horizontale Leiter (Monkey Bars)." + }, + "8": { + "then": "Die Fitness-Station hat eine Sprossenwand zum Klettern." + }, + "9": { + "then": "Die Fitness-Station hat Pfosten für Slalomübungen." + }, "10": { "then": "Die Fitness-Station hat Trittsteine." }, @@ -4945,9 +4969,6 @@ "19": { "then": "Die Fitness-Station hat Kampfseile (battle ropes)." }, - "2": { - "then": "Die Fitness-Station hat eine Einrichtung für Sit-ups." - }, "20": { "then": "Die Fitness-Station hat ein Fahrradergometer." }, @@ -4962,27 +4983,6 @@ }, "24": { "then": "Die Fitness-Station hat eine Slackline." - }, - "3": { - "then": "Die Fitness-Station hat eine Vorrichtung für Liegestütze. In der Regel eine oder mehrere niedrige Reckstangen." - }, - "4": { - "then": "Die Fitness-Station hat Stangen zum Dehnen." - }, - "5": { - "then": "Die Fitness-Station hat eine Vorrichtung für Rückenstrecker (Hyperextensions)." - }, - "6": { - "then": "Die Fitness-Station hat Ringe für Gymnastikübungen." - }, - "7": { - "then": "Die Fitness-Station hat eine horizontale Leiter (Monkey Bars)." - }, - "8": { - "then": "Die Fitness-Station hat eine Sprossenwand zum Klettern." - }, - "9": { - "then": "Die Fitness-Station hat Pfosten für Slalomübungen." } }, "question": "Welche Übungsgeräte gibt es an dieser Fitness-Station?" @@ -5102,21 +5102,6 @@ "1": { "then": "Dies ist eine Pommesbude" }, - "10": { - "then": "Hier werden chinesische Gerichte serviert" - }, - "11": { - "then": "Hier werden griechische Gerichte serviert" - }, - "12": { - "then": "Hier werden indische Gerichte serviert" - }, - "13": { - "then": "Hier werden türkische Gerichte serviert" - }, - "14": { - "then": "Hier werden thailändische Gerichte serviert" - }, "2": { "then": "Bietet vorwiegend Pastagerichte an" }, @@ -5140,6 +5125,21 @@ }, "9": { "then": "Hier werden französische Gerichte serviert" + }, + "10": { + "then": "Hier werden chinesische Gerichte serviert" + }, + "11": { + "then": "Hier werden griechische Gerichte serviert" + }, + "12": { + "then": "Hier werden indische Gerichte serviert" + }, + "13": { + "then": "Hier werden türkische Gerichte serviert" + }, + "14": { + "then": "Hier werden thailändische Gerichte serviert" } }, "question": "Was für Essen gibt es hier?", @@ -5777,6 +5777,30 @@ "1": { "then": "Dies ist ein Auditorium" }, + "2": { + "then": "Dies ist ein Schlafzimmer" + }, + "3": { + "then": "Dies ist eine Kapelle" + }, + "4": { + "then": "Dies ist ein Klassenzimmer" + }, + "5": { + "then": "Dies ist ein Klassenzimmer" + }, + "6": { + "then": "Dies ist ein Computerraum" + }, + "7": { + "then": "Dies ist ein Konferenzraum" + }, + "8": { + "then": "Dies ist eine Krypta" + }, + "9": { + "then": "Dies ist eine Küche" + }, "10": { "then": "Dies ist ein Labor" }, @@ -5807,9 +5831,6 @@ "19": { "then": "Dies ist ein Lagerraum" }, - "2": { - "then": "Dies ist ein Schlafzimmer" - }, "20": { "then": "Dies ist ein Technikraum" }, @@ -5818,27 +5839,6 @@ }, "22": { "then": "Dies ist ein Wartezimmer" - }, - "3": { - "then": "Dies ist eine Kapelle" - }, - "4": { - "then": "Dies ist ein Klassenzimmer" - }, - "5": { - "then": "Dies ist ein Klassenzimmer" - }, - "6": { - "then": "Dies ist ein Computerraum" - }, - "7": { - "then": "Dies ist ein Konferenzraum" - }, - "8": { - "then": "Dies ist eine Krypta" - }, - "9": { - "then": "Dies ist eine Küche" } }, "question": "Wie wird dieser Raum genutzt?" @@ -6493,19 +6493,6 @@ } } }, - "10": { - "options": { - "0": { - "question": "Alle Notizen" - }, - "1": { - "question": "Importnotizen ausblenden" - }, - "2": { - "question": "Nur Importnotizen anzeigen" - } - } - }, "2": { "options": { "0": { @@ -6561,6 +6548,19 @@ "question": "Nur offene Notizen anzeigen" } } + }, + "10": { + "options": { + "0": { + "question": "Alle Notizen" + }, + "1": { + "question": "Importnotizen ausblenden" + }, + "2": { + "question": "Nur Importnotizen anzeigen" + } + } } }, "name": "OpenStreetMap-Hinweise", @@ -6889,21 +6889,6 @@ "1": { "then": "Dies ist ein normaler Stellplatz." }, - "10": { - "then": "Dies ist ein Stellplatz, der für Eltern mit Kindern reserviert ist." - }, - "11": { - "then": "Dies ist ein Stellplatz, der für das Personal reserviert ist." - }, - "12": { - "then": "Dies ist ein Stellplatz, der für Taxis reserviert ist." - }, - "13": { - "then": "Dies ist ein Stellplatz, der für Fahrzeuge mit Anhänger reserviert ist." - }, - "14": { - "then": "Dies ist ein Stellplatz, der für Carsharing reserviert ist." - }, "2": { "then": "Dies ist ein Behindertenstellplatz." }, @@ -6927,6 +6912,21 @@ }, "9": { "then": "Dies ist ein Stellplatz, der für Motorräder reserviert ist." + }, + "10": { + "then": "Dies ist ein Stellplatz, der für Eltern mit Kindern reserviert ist." + }, + "11": { + "then": "Dies ist ein Stellplatz, der für das Personal reserviert ist." + }, + "12": { + "then": "Dies ist ein Stellplatz, der für Taxis reserviert ist." + }, + "13": { + "then": "Dies ist ein Stellplatz, der für Fahrzeuge mit Anhänger reserviert ist." + }, + "14": { + "then": "Dies ist ein Stellplatz, der für Carsharing reserviert ist." } }, "question": "Welche Art von Stellplatz ist dies?" @@ -7518,21 +7518,6 @@ "1": { "then": "2-Cent-Münzen werden akzeptiert" }, - "10": { - "then": "20-Centime-Münzen werden akzeptiert" - }, - "11": { - "then": "½-Schweizer Franken-Münzen werden akzeptiert" - }, - "12": { - "then": "1-Schweizer Franken-Münzen werden akzeptiert" - }, - "13": { - "then": "2-Schweizer Franken-Münzen werden akzeptiert" - }, - "14": { - "then": "5-Schweizer Franken-Münzen werden akzeptiert" - }, "2": { "then": "5-Cent-Münzen werden akzeptiert" }, @@ -7556,6 +7541,21 @@ }, "9": { "then": "10-Centime-Münzen werden akzeptiert" + }, + "10": { + "then": "20-Centime-Münzen werden akzeptiert" + }, + "11": { + "then": "½-Schweizer Franken-Münzen werden akzeptiert" + }, + "12": { + "then": "1-Schweizer Franken-Münzen werden akzeptiert" + }, + "13": { + "then": "2-Schweizer Franken-Münzen werden akzeptiert" + }, + "14": { + "then": "5-Schweizer Franken-Münzen werden akzeptiert" } }, "question": "Mit welchen Münzen kann man hier bezahlen?" @@ -7568,15 +7568,6 @@ "1": { "then": "10-Euro-Scheine werden angenommen" }, - "10": { - "then": "100-Schweizer Franken-Scheine werden akzeptiert" - }, - "11": { - "then": "200-Schweizer Franken-Scheine werden akzeptiert" - }, - "12": { - "then": "1000-Schweizer Franken-Scheine werden akzeptiert" - }, "2": { "then": "20-Euro-Scheine werden angenommen" }, @@ -7600,6 +7591,15 @@ }, "9": { "then": "50-Schweizer Franken-Scheine werden akzeptiert" + }, + "10": { + "then": "100-Schweizer Franken-Scheine werden akzeptiert" + }, + "11": { + "then": "200-Schweizer Franken-Scheine werden akzeptiert" + }, + "12": { + "then": "1000-Schweizer Franken-Scheine werden akzeptiert" } }, "question": "Mit welchen Banknoten kann man hier bezahlen?" @@ -8050,6 +8050,30 @@ "1": { "question": "Recycling von Batterien" }, + "2": { + "question": "Recycling von Getränkekartons" + }, + "3": { + "question": "Recycling von Dosen" + }, + "4": { + "question": "Recycling von Kleidung" + }, + "5": { + "question": "Recycling von Speiseöl" + }, + "6": { + "question": "Recycling von Motoröl" + }, + "7": { + "question": "Recycling von Leuchtstoffröhren" + }, + "8": { + "question": "Recycling von Grünabfällen" + }, + "9": { + "question": "Recycling von Glasflaschen" + }, "10": { "question": "Recycling von Glas" }, @@ -8080,35 +8104,11 @@ "19": { "question": "Recycling von Restabfällen" }, - "2": { - "question": "Recycling von Getränkekartons" - }, "20": { "question": "Recycling von Druckerpatronen" }, "21": { "question": "Recycling von Fahrrädern" - }, - "3": { - "question": "Recycling von Dosen" - }, - "4": { - "question": "Recycling von Kleidung" - }, - "5": { - "question": "Recycling von Speiseöl" - }, - "6": { - "question": "Recycling von Motoröl" - }, - "7": { - "question": "Recycling von Leuchtstoffröhren" - }, - "8": { - "question": "Recycling von Grünabfällen" - }, - "9": { - "question": "Recycling von Glasflaschen" } } }, @@ -8176,6 +8176,30 @@ "1": { "then": "Getränkekartons können hier recycelt werden" }, + "2": { + "then": "Dosen können hier recycelt werden" + }, + "3": { + "then": "Kleidung kann hier recycelt werden" + }, + "4": { + "then": "Speiseöl kann hier recycelt werden" + }, + "5": { + "then": "Motoröl kann hier recycelt werden" + }, + "6": { + "then": "Hier können Leuchtstoffröhren recycelt werden" + }, + "7": { + "then": "Grünabfälle können hier recycelt werden" + }, + "8": { + "then": "Bio-Abfall kann hier recycelt werden" + }, + "9": { + "then": "Glasflaschen können hier recycelt werden" + }, "10": { "then": "Glas kann hier recycelt werden" }, @@ -8206,9 +8230,6 @@ "19": { "then": "Schuhe können hier recycelt werden" }, - "2": { - "then": "Dosen können hier recycelt werden" - }, "20": { "then": "Elektrokleingeräte können hier recycelt werden" }, @@ -8223,27 +8244,6 @@ }, "24": { "then": "Fahrräder können hier recycelt werden" - }, - "3": { - "then": "Kleidung kann hier recycelt werden" - }, - "4": { - "then": "Speiseöl kann hier recycelt werden" - }, - "5": { - "then": "Motoröl kann hier recycelt werden" - }, - "6": { - "then": "Hier können Leuchtstoffröhren recycelt werden" - }, - "7": { - "then": "Grünabfälle können hier recycelt werden" - }, - "8": { - "then": "Bio-Abfall kann hier recycelt werden" - }, - "9": { - "then": "Glasflaschen können hier recycelt werden" } }, "question": "Was kann hier recycelt werden?" @@ -9161,12 +9161,6 @@ "1": { "then": "Diese Straßenlaterne verwendet LEDs" }, - "10": { - "then": "Diese Straßenlaterne verwendet Hochdruck-Natriumdampflampen (orange mit weiß)" - }, - "11": { - "then": "Diese Straßenlaterne wird mit Gas beleuchtet" - }, "2": { "then": "Diese Straßenlaterne verwendet Glühlampenlicht" }, @@ -9190,6 +9184,12 @@ }, "9": { "then": "Diese Straßenlaterne verwendet Niederdruck-Natriumdampflampen (einfarbig orange)" + }, + "10": { + "then": "Diese Straßenlaterne verwendet Hochdruck-Natriumdampflampen (orange mit weiß)" + }, + "11": { + "then": "Diese Straßenlaterne wird mit Gas beleuchtet" } }, "question": "Mit welcher Art von Beleuchtung arbeitet diese Straßenlaterne?" @@ -10367,6 +10367,30 @@ "1": { "question": "Verkauf von Getränken" }, + "2": { + "question": "Verkauf von Süßigkeiten" + }, + "3": { + "question": "Verkauf von Lebensmitteln" + }, + "4": { + "question": "Verkauf von Zigaretten" + }, + "5": { + "question": "Verkauf von Kondomen" + }, + "6": { + "question": "Verkauf von Kaffee" + }, + "7": { + "question": "Verkauf von Trinkwasser" + }, + "8": { + "question": "Verkauf von Zeitungen" + }, + "9": { + "question": "Verkauf von Fahrradschläuchen" + }, "10": { "question": "Verkauf von Milch" }, @@ -10397,9 +10421,6 @@ "19": { "question": "Verkauf von Blumen" }, - "2": { - "question": "Verkauf von Süßigkeiten" - }, "20": { "question": "Verkauf von Parkscheinen" }, @@ -10423,27 +10444,6 @@ }, "27": { "question": "Verkauf von Fahrradschlössern" - }, - "3": { - "question": "Verkauf von Lebensmitteln" - }, - "4": { - "question": "Verkauf von Zigaretten" - }, - "5": { - "question": "Verkauf von Kondomen" - }, - "6": { - "question": "Verkauf von Kaffee" - }, - "7": { - "question": "Verkauf von Trinkwasser" - }, - "8": { - "question": "Verkauf von Zeitungen" - }, - "9": { - "question": "Verkauf von Fahrradschläuchen" } } } @@ -10490,6 +10490,30 @@ "1": { "then": "Süßigkeiten werden verkauft" }, + "2": { + "then": "Lebensmittel werden verkauft" + }, + "3": { + "then": "Zigaretten werden verkauft" + }, + "4": { + "then": "Kondome werden verkauft" + }, + "5": { + "then": "Kaffee wird verkauft" + }, + "6": { + "then": "Trinkwasser wird verkauft" + }, + "7": { + "then": "Zeitungen werden verkauft" + }, + "8": { + "then": "Fahrradschläuche werden verkauft" + }, + "9": { + "then": "Milch wird verkauft" + }, "10": { "then": "Brot wird verkauft" }, @@ -10520,9 +10544,6 @@ "19": { "then": "Parkscheine werden verkauft" }, - "2": { - "then": "Lebensmittel werden verkauft" - }, "20": { "then": "Souvenirmünzen werden verkauft" }, @@ -10543,27 +10564,6 @@ }, "26": { "then": "Fahrradschlösser werden verkauft" - }, - "3": { - "then": "Zigaretten werden verkauft" - }, - "4": { - "then": "Kondome werden verkauft" - }, - "5": { - "then": "Kaffee wird verkauft" - }, - "6": { - "then": "Trinkwasser wird verkauft" - }, - "7": { - "then": "Zeitungen werden verkauft" - }, - "8": { - "then": "Fahrradschläuche werden verkauft" - }, - "9": { - "then": "Milch wird verkauft" } }, "question": "Was wird in diesem Automaten verkauft?", @@ -10892,4 +10892,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/en.json b/langs/layers/en.json index 0f2e3d6b5..14ed9817b 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4662,6 +4662,18 @@ "render": "Extinguishers" } }, + "favourite": { + "description": "A generic map layer which shows locations that a contributor marked as favourite", + "name": "Favourites", + "tagRenderings": { + "Explanation": { + "render": "You marked this location as a personal favourite. As such, it is shown on every map you load." + } + }, + "title": { + "render": "Favourite location" + } + }, "filters": { "filter": { "0": { diff --git a/langs/layers/es.json b/langs/layers/es.json index 8c4f0fce6..8d002852d 100644 --- a/langs/layers/es.json +++ b/langs/layers/es.json @@ -35,16 +35,6 @@ "1": { "title": "un mupi" }, - "10": { - "description": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales", - "title": "un señal" - }, - "11": { - "title": "una escultura" - }, - "12": { - "title": "una pared pintada" - }, "2": { "title": "un mupi sobre la pared" }, @@ -71,6 +61,16 @@ }, "9": { "title": "un tótem" + }, + "10": { + "description": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales", + "title": "un señal" + }, + "11": { + "title": "una escultura" + }, + "12": { + "title": "una pared pintada" } }, "tagRenderings": { @@ -165,9 +165,6 @@ "1": { "then": "Esto es un tablón de anuncios" }, - "10": { - "then": "Esto es una pared pintada" - }, "2": { "then": "Esto es una columna" }, @@ -191,6 +188,9 @@ }, "9": { "then": "Esto es un tótem" + }, + "10": { + "then": "Esto es una pared pintada" } }, "question": "¿Qué tipo de elemento publicitario es?", @@ -205,9 +205,6 @@ "1": { "then": "Tablon de anuncios" }, - "10": { - "then": "Pared Pintada" - }, "2": { "then": "Mupi" }, @@ -231,6 +228,9 @@ }, "9": { "then": "Tótem" + }, + "10": { + "then": "Pared Pintada" } } } @@ -353,15 +353,6 @@ "1": { "then": "Mural" }, - "10": { - "then": "Azulejo (Baldosas decorativas Españolas y Portuguesas)" - }, - "11": { - "then": "Cerámica" - }, - "12": { - "then": "Tallado en madera" - }, "2": { "then": "Pintura" }, @@ -385,6 +376,15 @@ }, "9": { "then": "Relieve" + }, + "10": { + "then": "Azulejo (Baldosas decorativas Españolas y Portuguesas)" + }, + "11": { + "then": "Cerámica" + }, + "12": { + "then": "Tallado en madera" } }, "question": "¿Qué tipo de obra es esta pieza?", @@ -1768,27 +1768,6 @@ "0": { "question": "Todos los conectores" }, - "10": { - "question": "Tiene un conector
Tipo 2 con cable (mennekes)
" - }, - "11": { - "question": "Tiene un conector
Tesla Supercharger CCS (un tipo2_css de marca)
" - }, - "12": { - "question": "Tiene un conector
Tesla Supercharger (destination)
" - }, - "13": { - "question": "Tiene un conector
Tesla Supercharger (Destination) (Tipo2 A con un cable de marca tesla)
" - }, - "14": { - "question": "Tiene un conector
USB para cargar teléfonos y dispositivos electrónicos pequeños
" - }, - "15": { - "question": "Tiene un conector
Bosch Active Connect con 3 pines y cable
" - }, - "16": { - "question": "Tiene un conector
Bosch Active Connect con 5 pines y cable
" - }, "2": { "question": "Tiene un conector
enchufe de pared Europeo con un pin de tierra (CEE7/4 tipo E)
" }, @@ -1812,6 +1791,27 @@ }, "9": { "question": "Tiene un conector
Tipo 2 CCS (mennekes)
" + }, + "10": { + "question": "Tiene un conector
Tipo 2 con cable (mennekes)
" + }, + "11": { + "question": "Tiene un conector
Tesla Supercharger CCS (un tipo2_css de marca)
" + }, + "12": { + "question": "Tiene un conector
Tesla Supercharger (destination)
" + }, + "13": { + "question": "Tiene un conector
Tesla Supercharger (Destination) (Tipo2 A con un cable de marca tesla)
" + }, + "14": { + "question": "Tiene un conector
USB para cargar teléfonos y dispositivos electrónicos pequeños
" + }, + "15": { + "question": "Tiene un conector
Bosch Active Connect con 3 pines y cable
" + }, + "16": { + "question": "Tiene un conector
Bosch Active Connect con 5 pines y cable
" } } } @@ -1866,6 +1866,30 @@ "1": { "then": "Enchufe de pared Schuko sin pin de tierra (CEE7/4 tipo F)" }, + "2": { + "then": "Enchufe de pared Europeo con pin de tierra (CEE7/4 tipo E)" + }, + "3": { + "then": "Enchufe de pared Europeo con pin de tierra (CEE7/4 tipo E)" + }, + "4": { + "then": "Chademo" + }, + "5": { + "then": "Chademo" + }, + "6": { + "then": "Tipo 1 con cable (J1772)" + }, + "7": { + "then": "Tipo 1 con cable (J1772)" + }, + "8": { + "then": "Tipo 1 sin cable (J1772)" + }, + "9": { + "then": "Tipo 1 sin cable (J1772)" + }, "10": { "then": "CSS Tipo 1 (también conocido como Tipo 1 Combo)" }, @@ -1896,9 +1920,6 @@ "19": { "then": "Tipo 2 con cable (mennekes)" }, - "2": { - "then": "Enchufe de pared Europeo con pin de tierra (CEE7/4 tipo E)" - }, "20": { "then": "CCS Supercargador Tesla (un tipo2_css con marca)" }, @@ -1929,32 +1950,11 @@ "29": { "then": "Bosch Active Connect con 3 pines y cable" }, - "3": { - "then": "Enchufe de pared Europeo con pin de tierra (CEE7/4 tipo E)" - }, "30": { "then": "Bosch Active Connect con 5 pines y cable" }, "31": { "then": "Bosch Active Connect con 5 pines y cable" - }, - "4": { - "then": "Chademo" - }, - "5": { - "then": "Chademo" - }, - "6": { - "then": "Tipo 1 con cable (J1772)" - }, - "7": { - "then": "Tipo 1 con cable (J1772)" - }, - "8": { - "then": "Tipo 1 sin cable (J1772)" - }, - "9": { - "then": "Tipo 1 sin cable (J1772)" } }, "question": "¿Qué tipo de conexiones de carga están disponibles aquí?" @@ -2349,12 +2349,6 @@ "1": { "then": "Este carril bici está pavimentado" }, - "10": { - "then": "Este carril bici está hecho de gravilla" - }, - "12": { - "then": "Este carril bici está hecho de tierra natural" - }, "2": { "then": "Este carril bici está hecho de asfalto" }, @@ -2369,6 +2363,12 @@ }, "9": { "then": "Este carril bici está hecho de grava" + }, + "10": { + "then": "Este carril bici está hecho de gravilla" + }, + "12": { + "then": "Este carril bici está hecho de tierra natural" } }, "question": "¿De qué superficie está hecho este carril bici?", @@ -2414,9 +2414,6 @@ "1": { "then": "Este carril bici está pavimentado" }, - "10": { - "then": "Este carril bici está hecho de gravilla" - }, "2": { "then": "Este carril bici está hecho de asfalto" }, @@ -2428,6 +2425,9 @@ }, "9": { "then": "Este carril bici está hecho de grava" + }, + "10": { + "then": "Este carril bici está hecho de gravilla" } }, "question": "¿De qué esta hecha la superficie de esta calle?", @@ -3069,18 +3069,6 @@ "0": { "then": "Esto es una pizzería" }, - "10": { - "then": "Aquí se sirven platos Chinos" - }, - "11": { - "then": "Aquí se sirven platos Griegos" - }, - "12": { - "then": "Aquí se sirven platos Indios" - }, - "13": { - "then": "Aquí se sirven platos Turcos" - }, "2": { "then": "Principalmente sirve pasta" }, @@ -3101,6 +3089,18 @@ }, "9": { "then": "Aquí se sirven platos Franceses" + }, + "10": { + "then": "Aquí se sirven platos Chinos" + }, + "11": { + "then": "Aquí se sirven platos Griegos" + }, + "12": { + "then": "Aquí se sirven platos Indios" + }, + "13": { + "then": "Aquí se sirven platos Turcos" } }, "question": "¿Qué tipo de comida sirven aquí?", @@ -3499,19 +3499,6 @@ } } }, - "10": { - "options": { - "0": { - "question": "Todas las notas" - }, - "1": { - "question": "Ocultar las notas de importación" - }, - "2": { - "question": "Solo mostrar las notas de importación" - } - } - }, "2": { "options": { "0": { @@ -3567,6 +3554,19 @@ "question": "Solo mostrar las notas abiertas" } } + }, + "10": { + "options": { + "0": { + "question": "Todas las notas" + }, + "1": { + "question": "Ocultar las notas de importación" + }, + "2": { + "question": "Solo mostrar las notas de importación" + } + } } }, "name": "Notas de OpenStreetMap", @@ -4182,6 +4182,24 @@ "1": { "question": "Reciclaje de baterías" }, + "3": { + "question": "Reciclaje de latas" + }, + "4": { + "question": "Reciclaje de ropa" + }, + "5": { + "question": "Reciclaje de aceite de cocina" + }, + "6": { + "question": "Reciclaje de aceite de motor" + }, + "8": { + "question": "Reciclaje de residuos orgánicos" + }, + "9": { + "question": "Reciclaje de botellas de cristal" + }, "10": { "question": "Reciclaje de cristal" }, @@ -4208,24 +4226,6 @@ }, "18": { "question": "Reciclaje de pequeños electrodomésticos" - }, - "3": { - "question": "Reciclaje de latas" - }, - "4": { - "question": "Reciclaje de ropa" - }, - "5": { - "question": "Reciclaje de aceite de cocina" - }, - "6": { - "question": "Reciclaje de aceite de motor" - }, - "8": { - "question": "Reciclaje de residuos orgánicos" - }, - "9": { - "question": "Reciclaje de botellas de cristal" } } } @@ -4268,6 +4268,27 @@ "0": { "then": "Aquí se pueden reciclar baterías" }, + "2": { + "then": "Aquí se pueden reciclar latas" + }, + "3": { + "then": "Aquí se puede reciclar ropa" + }, + "4": { + "then": "Aquí se puede reciclar aceite de cocina" + }, + "5": { + "then": "Aquí se puede reciclar aceite de motor" + }, + "7": { + "then": "Los residuos orgánicos pueden reciclarse aquí" + }, + "8": { + "then": "Aquí se pueden reciclar residuos orgánicos" + }, + "9": { + "then": "Aquí se pueden reciclar botellas de cristal" + }, "10": { "then": "Aquí se puede reciclar cristal" }, @@ -4294,27 +4315,6 @@ }, "19": { "then": "El calzado se puede reciclar aquí" - }, - "2": { - "then": "Aquí se pueden reciclar latas" - }, - "3": { - "then": "Aquí se puede reciclar ropa" - }, - "4": { - "then": "Aquí se puede reciclar aceite de cocina" - }, - "5": { - "then": "Aquí se puede reciclar aceite de motor" - }, - "7": { - "then": "Los residuos orgánicos pueden reciclarse aquí" - }, - "8": { - "then": "Aquí se pueden reciclar residuos orgánicos" - }, - "9": { - "then": "Aquí se pueden reciclar botellas de cristal" } }, "question": "¿Qué se puede reciclar aquí?" @@ -4665,12 +4665,6 @@ "1": { "then": "Esta lámpara utiliza LEDs" }, - "10": { - "then": "Esta lámpara utiliza lámparas de sodio de alta presión (naranja con blanco)" - }, - "11": { - "then": "Esta lampara se ilumina con gas" - }, "2": { "then": "Esta lámpara utiliza iluminación incandescente" }, @@ -4691,6 +4685,12 @@ }, "9": { "then": "Esta lámpara utiliza lámparas de sodio de baja presión (naranja monocromo)" + }, + "10": { + "then": "Esta lámpara utiliza lámparas de sodio de alta presión (naranja con blanco)" + }, + "11": { + "then": "Esta lampara se ilumina con gas" } }, "question": "¿Qué tipo de iluminación utiliza esta lámpara?" @@ -5262,4 +5262,4 @@ } } } -} +} \ No newline at end of file diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 35f8706f0..8a4b3736c 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4364,6 +4364,18 @@ "render": "Brandblussers" } }, + "favourite": { + "description": "Een laag met persoonlijke favourieten", + "name": "Favorieten", + "tagRenderings": { + "Explanation": { + "render": "Je hebt deze locatie als persoonlijke favoriet aangeduid en worden op alle MapComplete-kaarten getoond." + } + }, + "title": { + "render": "Favoriete locatie" + } + }, "filters": { "filter": { "0": { diff --git a/langs/themes/de.json b/langs/themes/de.json index 6e9ebb26d..cc768eb16 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -1024,33 +1024,6 @@ "onwheels": { "description": "Auf dieser Karte können Sie öffentlich zugängliche Orte für Rollstuhlfahrer ansehen, bearbeiten oder hinzufügen", "layers": { - "19": { - "override": { - "=title": { - "render": "Statistik" - } - } - }, - "20": { - "override": { - "+tagRenderings": { - "0": { - "render": { - "special": { - "text": "Import" - } - } - }, - "1": { - "render": { - "special": { - "message": "Alle vorgeschlagenen Tags hinzufügen" - } - } - } - } - } - }, "4": { "override": { "filter": { @@ -1093,6 +1066,33 @@ "override": { "name": "Barrierefreie Parkplätze" } + }, + "19": { + "override": { + "=title": { + "render": "Statistik" + } + } + }, + "20": { + "override": { + "+tagRenderings": { + "0": { + "render": { + "special": { + "text": "Import" + } + } + }, + "1": { + "render": { + "special": { + "message": "Alle vorgeschlagenen Tags hinzufügen" + } + } + } + } + } } }, "title": "Auf Rädern" @@ -1253,6 +1253,10 @@ "stations": { "description": "Bahnhofsdetails ansehen, bearbeiten und hinzufügen", "layers": { + "3": { + "description": "Ebene mit Bahnhöfen", + "name": "Bahnhöfe" + }, "16": { "description": "Anzeigen der Züge, die von diesem Bahnhof abfahren", "name": "Abfahrtstafeln", @@ -1284,10 +1288,6 @@ "title": { "render": "Abfahrtstafel" } - }, - "3": { - "description": "Ebene mit Bahnhöfen", - "name": "Bahnhöfe" } }, "title": "Bahnhöfe" @@ -1458,4 +1458,4 @@ "shortDescription": "Eine Karte mit Abfalleimern", "title": "Abfalleimer" } -} +} \ No newline at end of file diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 3d49a619b..d66b0bb91 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -765,10 +765,6 @@ video { float: left; } -.m-8 { - margin: 2rem; -} - .m-4 { margin: 1rem; } @@ -781,6 +777,10 @@ video { margin: 0px; } +.m-8 { + margin: 2rem; +} + .m-2 { margin: 0.5rem; } @@ -841,6 +841,10 @@ video { margin-right: 3rem; } +.mb-4 { + margin-bottom: 1rem; +} + .mt-4 { margin-top: 1rem; } @@ -877,10 +881,6 @@ video { margin-right: 0.25rem; } -.mb-4 { - margin-bottom: 1rem; -} - .ml-1 { margin-left: 0.25rem; } diff --git a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts new file mode 100644 index 000000000..4589d9493 --- /dev/null +++ b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts @@ -0,0 +1,157 @@ +import StaticFeatureSource from "./StaticFeatureSource" +import { Feature } from "geojson" +import { Store, UIEventSource } from "../../UIEventSource" +import { OsmConnection } from "../../Osm/OsmConnection" +import { OsmId } from "../../../Models/OsmFeature" +import { GeoOperations } from "../../GeoOperations" +import FeaturePropertiesStore from "../Actors/FeaturePropertiesStore" +import { IndexedFeatureSource } from "../FeatureSource" +import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" + +/** + * Generates the favourites from the preferences and marks them as favourite + */ +export default class FavouritesFeatureSource extends StaticFeatureSource { + public static readonly prefix = "mapcomplete-favourite-" + private readonly _osmConnection: OsmConnection + + constructor( + connection: OsmConnection, + indexedSource: FeaturePropertiesStore, + allFeatures: IndexedFeatureSource, + layout: LayoutConfig + ) { + const detectedIds = new UIEventSource>(undefined) + const features: Store = connection.preferencesHandler.preferences.map( + (prefs) => { + const feats: Feature[] = [] + const allIds = new Set() + for (const key in prefs) { + if (!key.startsWith(FavouritesFeatureSource.prefix)) { + continue + } + const id = key.substring(FavouritesFeatureSource.prefix.length) + const osmId = id.replace("-", "/") + if (id.indexOf("-property-") > 0 || id.indexOf("-layer") > 0) { + continue + } + allIds.add(osmId) + const geometry = <[number, number]>JSON.parse(prefs[key]) + const properties = FavouritesFeatureSource.getPropertiesFor(connection, id) + properties._orig_layer = prefs[FavouritesFeatureSource.prefix + id + "-layer"] + if (layout.layers.some((l) => l.id === properties._orig_layer)) { + continue + } + properties.id = osmId + properties._favourite = "yes" + feats.push({ + type: "Feature", + properties, + geometry: { + type: "Point", + coordinates: geometry, + }, + }) + } + console.log("Favouritess are", feats) + detectedIds.setData(allIds) + return feats + } + ) + + super(features) + + this._osmConnection = connection + detectedIds.addCallbackAndRunD((detected) => + this.markFeatures(detected, indexedSource, allFeatures) + ) + // We use the indexedFeatureSource as signal to update + allFeatures.features.map((_) => + this.markFeatures(detectedIds.data, indexedSource, allFeatures) + ) + } + + private static getPropertiesFor( + osmConnection: OsmConnection, + id: string + ): Record { + const properties: Record = {} + const prefs = osmConnection.preferencesHandler.preferences.data + const minLength = FavouritesFeatureSource.prefix.length + id.length + "-property-".length + for (const key in prefs) { + if (key.length < minLength) { + continue + } + if (!key.startsWith(FavouritesFeatureSource.prefix + id)) { + continue + } + const propertyName = key.substring(minLength) + properties[propertyName] = prefs[key] + } + return properties + } + + public markAsFavourite( + feature: Feature, + layer: string, + theme: string, + tags: UIEventSource & { id: OsmId }>, + isFavourite: boolean = true + ) { + { + const id = tags.data.id.replace("/", "-") + const pref = this._osmConnection.GetPreference("favourite-" + id) + if (isFavourite) { + const center = GeoOperations.centerpointCoordinates(feature) + pref.setData(JSON.stringify(center)) + this._osmConnection.GetPreference("favourite-" + id + "-layer").setData(layer) + this._osmConnection.GetPreference("favourite-" + id + "-theme").setData(theme) + + for (const key in tags.data) { + const pref = this._osmConnection.GetPreference( + "favourite-" + id + "-property-" + key.replaceAll(":", "__") + ) + pref.setData(tags.data[key]) + } + } else { + this._osmConnection.preferencesHandler.removeAllWithPrefix( + "mapcomplete-favourite-" + id + ) + } + } + if (isFavourite) { + tags.data._favourite = "yes" + tags.ping() + } else { + delete tags.data._favourite + tags.ping() + } + } + + private markFeatures( + detected: Set, + featureProperties: FeaturePropertiesStore, + allFeatures: IndexedFeatureSource + ) { + const feature = allFeatures.features.data + for (const f of feature) { + const id = f.properties.id + if (!id) { + continue + } + const store = featureProperties.getStore(id) + const origValue = store.data._favourite + if (detected.has(id)) { + if (origValue !== "yes") { + store.data._favourite = "yes" + store.ping() + } + } else { + if (origValue) { + store.data._favourite = "" + store.ping() + } + } + } + } +} diff --git a/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts b/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts index 669c86a11..cec3f4de9 100644 --- a/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts @@ -6,10 +6,14 @@ import FilteringFeatureSource from "./FilteringFeatureSource" import LayerState from "../../State/LayerState" export default class NearbyFeatureSource implements FeatureSource { + private readonly _result = new UIEventSource(undefined) + public readonly features: Store private readonly _targetPoint: Store<{ lon: number; lat: number }> private readonly _numberOfNeededFeatures: number + private readonly _layerState?: LayerState private readonly _currentZoom: Store + private readonly _allSources: Store<{ feat: Feature; d: number }[]>[] = [] constructor( targetPoint: Store<{ lon: number; lat: number }>, @@ -18,41 +22,44 @@ export default class NearbyFeatureSource implements FeatureSource { layerState?: LayerState, currentZoom?: Store ) { + this._layerState = layerState this._targetPoint = targetPoint.stabilized(100) this._numberOfNeededFeatures = numberOfNeededFeatures this._currentZoom = currentZoom.stabilized(500) - const allSources: Store<{ feat: Feature; d: number }[]>[] = [] + this.features = Stores.ListStabilized(this._result) + + sources.forEach((source, layer) => {}) + } + + public registerSource(source: FeatureSource, layerId: string) { let minzoom = 999 - - const result = new UIEventSource(undefined) - this.features = Stores.ListStabilized(result) - - function update() { - let features: { feat: Feature; d: number }[] = [] - for (const src of allSources) { - features.push(...src.data) - } - features.sort((a, b) => a.d - b.d) - if (numberOfNeededFeatures !== undefined) { - features = features.slice(0, numberOfNeededFeatures) - } - result.setData(features.map((f) => f.feat)) + const flayer = this._layerState?.filteredLayers.get(layerId) + if (!flayer) { + return } - - sources.forEach((source, layer) => { - const flayer = layerState?.filteredLayers.get(layer) - minzoom = Math.min(minzoom, flayer.layerDef.minzoom) - const calcSource = this.createSource( - source.features, - flayer.layerDef.minzoom, - flayer.isDisplayed - ) - calcSource.addCallbackAndRunD((features) => { - update() - }) - allSources.push(calcSource) + minzoom = Math.min(minzoom, flayer.layerDef.minzoom) + const calcSource = this.createSource( + source.features, + flayer.layerDef.minzoom, + flayer.isDisplayed + ) + calcSource.addCallbackAndRunD((features) => { + this.update() }) + this._allSources.push(calcSource) + } + + private update() { + let features: { feat: Feature; d: number }[] = [] + for (const src of this._allSources) { + features.push(...src.data) + } + features.sort((a, b) => a.d - b.d) + if (this._numberOfNeededFeatures !== undefined) { + features = features.slice(0, this._numberOfNeededFeatures) + } + this._result.setData(features.map((f) => f.feat)) } /** diff --git a/src/Logic/Osm/OsmPreferences.ts b/src/Logic/Osm/OsmPreferences.ts index 778b74136..e36536258 100644 --- a/src/Logic/Osm/OsmPreferences.ts +++ b/src/Logic/Osm/OsmPreferences.ts @@ -285,4 +285,13 @@ export class OsmPreferences { } ) } + + removeAllWithPrefix(prefix: string) { + for (const key in this.preferences.data) { + if (key.startsWith(prefix)) { + this.GetPreference(key, undefined, { prefix: "" }).setData(undefined) + console.log("Clearing preference", key) + } + } + } } diff --git a/src/Models/Constants.ts b/src/Models/Constants.ts index f15232e3d..bf2e0e5cc 100644 --- a/src/Models/Constants.ts +++ b/src/Models/Constants.ts @@ -23,6 +23,7 @@ export default class Constants { "gps_track", "range", "last_click", + "favourite", ] as const /** * Special layers which are not included in a theme by default @@ -131,6 +132,8 @@ export default class Constants { "clock", "invalid", "close", + "heart", + "heart_outline", ] as const public static readonly defaultPinIcons: string[] = Constants._defaultPinIcons diff --git a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts index fd041335c..00b84c764 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -26,7 +26,7 @@ import predifined_filters from "../../../../assets/layers/filters/filters.json" import { TagConfigJson } from "../Json/TagConfigJson" import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson" import ValidationUtils from "./ValidationUtils" -import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization" +import { RenderingSpecification } from "../../../UI/SpecialVisualization" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" import { ConfigMeta } from "../../../UI/Studio/configMeta" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" @@ -639,6 +639,13 @@ export class AddEditingElements extends DesugaringStep { json.tagRenderings.push(this._desugaring.tagRenderings.get("last_edit")) } + if (!usedSpecialFunctions.has("favourite_status")) { + json.tagRenderings.push({ + id: "favourite_status", + render: { "*": "{favourite_status()}" }, + }) + } + if (!usedSpecialFunctions.has("all_tags")) { const trc: QuestionableTagRenderingConfigJson = { id: "all-tags", @@ -1193,6 +1200,31 @@ class ExpandMarkerRenderings extends DesugaringStep { } } +class AddFavouriteBadges extends DesugaringStep { + constructor() { + super( + "Adds the favourite heart to the title and the rendering badges", + [], + "AddFavouriteBadges" + ) + } + + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { + if (json.id === "favourite") { + return json + } + const pr = json.pointRendering?.[0] + if (pr) { + pr.iconBadges ??= [] + if (!pr.iconBadges.some((ti) => ti.if === "_favourite=yes")) { + pr.iconBadges.push({ if: "_favourite=yes", then: "circle:white;heart:red" }) + } + } + + return json + } +} + export class AddRatingBadge extends DesugaringStep { constructor() { super( @@ -1206,6 +1238,10 @@ export class AddRatingBadge extends DesugaringStep { if (!json.tagRenderings) { return json } + if (json.titleIcons.some((ti) => ti === "icons.rating" || ti["id"] === "rating")) { + // already added + return json + } const specialVis: Exclude[] = < Exclude[] @@ -1247,6 +1283,7 @@ export class PrepareLayer extends Fuse { ), new SetDefault("titleIcons", ["icons.defaults"]), new AddRatingBadge(), + new AddFavouriteBadges(), new On( "titleIcons", (layer) => diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts index 9002c3a9a..62a495bf7 100644 --- a/src/Models/ThemeConfig/Conversion/Validation.ts +++ b/src/Models/ThemeConfig/Conversion/Validation.ts @@ -968,7 +968,7 @@ export class ValidateTagRenderings extends Fuse { "Various validation on tagRenderingConfigs", new DetectShadowedMappings(layerConfig), new DetectConflictingAddExtraTags(), - new DetectNonErasedKeysInMappings(), + // new DetectNonErasedKeysInMappings(), new DetectMappingsWithImages(doesImageExist), new On("render", new ValidatePossibleLinks()), new On("question", new ValidatePossibleLinks()), diff --git a/src/Models/ThemeConfig/LayoutConfig.ts b/src/Models/ThemeConfig/LayoutConfig.ts index ce538d6b2..77ee2ef48 100644 --- a/src/Models/ThemeConfig/LayoutConfig.ts +++ b/src/Models/ThemeConfig/LayoutConfig.ts @@ -305,6 +305,9 @@ export default class LayoutConfig implements LayoutInformation { } for (const layer of this.layers) { if (!layer.source) { + if (layer.isShown?.matchesProperties(tags)) { + return layer + } continue } if (layer.source.osmTags.matchesProperties(tags)) { diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 0cc0119e6..a94ad07b4 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -58,6 +58,7 @@ import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLay import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager" import { Imgur } from "../Logic/ImageProviders/Imgur" import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSource" +import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource" /** * @@ -96,10 +97,11 @@ export default class ThemeViewState implements SpecialVisualizationState { readonly indexedFeatures: IndexedFeatureSource & LayoutSource readonly currentView: FeatureSource> readonly featuresInView: FeatureSource + readonly favourites: FavouritesFeatureSource /** * Contains a few (<10) >features that are near the center of the map. */ - readonly closestFeatures: FeatureSource + readonly closestFeatures: NearbyFeatureSource readonly newFeatures: WritableFeatureSource readonly layerState: LayerState readonly perLayer: ReadonlyMap @@ -220,8 +222,6 @@ export default class ThemeViewState implements SpecialVisualizationState { this.fullNodeDatabase ) - this.indexedFeatures = layoutSource - let currentViewIndex = 0 const empty = [] this.currentView = new StaticFeatureSource( @@ -242,13 +242,19 @@ export default class ThemeViewState implements SpecialVisualizationState { this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds) this.dataIsLoading = layoutSource.isLoading + this.indexedFeatures = layoutSource + this.featureProperties = new FeaturePropertiesStore(layoutSource) + this.favourites = new FavouritesFeatureSource( + this.osmConnection, + this.featureProperties, + layoutSource, + layout + ) - const indexedElements = this.indexedFeatures - this.featureProperties = new FeaturePropertiesStore(indexedElements) this.changes = new Changes( { dryRun: this.featureSwitches.featureSwitchIsTesting, - allElements: indexedElements, + allElements: layoutSource, featurePropertiesStore: this.featureProperties, osmConnection: this.osmConnection, historicalUserLocations: this.geolocation.historicalUserLocations, @@ -258,7 +264,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.historicalUserLocations = this.geolocation.historicalUserLocations this.newFeatures = new NewGeometryFromChangesFeatureSource( this.changes, - indexedElements, + layoutSource, this.featureProperties ) layoutSource.addSource(this.newFeatures) @@ -627,7 +633,10 @@ export default class ThemeViewState implements SpecialVisualizationState { ) ), current_view: this.currentView, + favourite: this.favourites, } + + this.closestFeatures.registerSource(specialLayers.favourite, "favourite") if (this.layout?.lockLocation) { const bbox = new BBox(this.layout.lockLocation) this.mapProperties.maxbounds.setData(bbox) @@ -663,12 +672,16 @@ export default class ThemeViewState implements SpecialVisualizationState { rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true) } + // enumarate all 'normal' layers and match them with the appropriate 'special' layer - if applicable this.layerState.filteredLayers.forEach((flayer) => { const id = flayer.layerDef.id const features: FeatureSource = specialLayers[id] if (features === undefined) { return } + if (id === "favourite") { + console.log("Matching special layer", id, flayer) + } this.featureProperties.trackFeatureSource(features) new ShowDataLayer(this.map, { diff --git a/src/UI/Base/LogoutButton.svelte b/src/UI/Base/LogoutButton.svelte index 020c411e1..0da388fb8 100644 --- a/src/UI/Base/LogoutButton.svelte +++ b/src/UI/Base/LogoutButton.svelte @@ -4,12 +4,10 @@ import Translations from "../i18n/Translations"; import Tr from "./Tr.svelte"; - export let osmConnection: OsmConnection + export let osmConnection: OsmConnection; - diff --git a/src/UI/Map/DynamicIcon.svelte b/src/UI/Map/DynamicIcon.svelte index 51d7668c1..e7a28699e 100644 --- a/src/UI/Map/DynamicIcon.svelte +++ b/src/UI/Map/DynamicIcon.svelte @@ -1,27 +1,7 @@ @@ -16,7 +16,9 @@ {#if marker && marker}
{#each marker as icon} - +
+ +
{/each}
{/if} diff --git a/src/UI/Map/Icon.svelte b/src/UI/Map/Icon.svelte index cccbef469..a6a49eb52 100644 --- a/src/UI/Map/Icon.svelte +++ b/src/UI/Map/Icon.svelte @@ -1,27 +1,29 @@ {#if icon} -
{#if icon === "pin"} - + {:else if icon === "square"} - + {:else if icon === "circle"} - + {:else if icon === "checkmark"} - + {:else if icon === "clock"} - + {:else if icon === "close"} - + {:else if icon === "crosshair"} - + {:else if icon === "help"} - + {:else if icon === "home"} - + {:else if icon === "invalid"} - + {:else if icon === "location"} - + {:else if icon === "location_empty"} - + {:else if icon === "location_locked"} - + {:else if icon === "note"} - + {:else if icon === "resolved"} - + {:else if icon === "ring"} - + {:else if icon === "scissors"} - + {:else if icon === "teardrop"} - + {:else if icon === "teardrop_with_hole_green"} - + {:else if icon === "triangle"} - + {:else if icon === "brick_wall_square"} - + {:else if icon === "brick_wall_round"} - + {:else if icon === "gps_arrow"} - + {:else if icon === "checkmark"} - + {:else if icon === "help"} - + {:else if icon === "close"} - + {:else if icon === "invalid"} - + + {:else if icon === "heart"} + + {:else if icon === "heart_outline"} + {:else} - + {/if} -
{/if} diff --git a/src/UI/Map/Marker.svelte b/src/UI/Map/Marker.svelte index f7b0d12e2..6afd6b68e 100644 --- a/src/UI/Map/Marker.svelte +++ b/src/UI/Map/Marker.svelte @@ -1,16 +1,18 @@ {#if icons !== undefined && icons.length > 0}
{#each icons as icon} - +
+ +
{/each}
{/if} diff --git a/src/UI/Map/ShowDataLayer.ts b/src/UI/Map/ShowDataLayer.ts index 33be0dcde..2f286148a 100644 --- a/src/UI/Map/ShowDataLayer.ts +++ b/src/UI/Map/ShowDataLayer.ts @@ -12,11 +12,9 @@ import { Feature, Point } from "geojson" import LineRenderingConfig from "../../Models/ThemeConfig/LineRenderingConfig" import { Utils } from "../../Utils" import * as range_layer from "../../../assets/layers/range/range.json" -import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter" import FilteredLayer from "../../Models/FilteredLayer" import SimpleFeatureSource from "../../Logic/FeatureSource/Sources/SimpleFeatureSource" -import { CLIENT_RENEG_LIMIT } from "tls" class PointRenderingLayer { private readonly _config: PointRenderingConfig diff --git a/src/UI/Popup/AllTagsPanel.svelte b/src/UI/Popup/AllTagsPanel.svelte index 81bc9219e..f4d3dd526 100644 --- a/src/UI/Popup/AllTagsPanel.svelte +++ b/src/UI/Popup/AllTagsPanel.svelte @@ -18,7 +18,7 @@ ...(state?.layoutToUse?.layers?.map((l) => l.calculatedTags?.map((c) => c[0]) ?? []) ?? []) ) - const allTags = tags.map((tags) => { + const allTags = tags.mapD((tags) => { const parts: (string | BaseUIElement)[][] = [] for (const key in tags) { let v = tags[key] diff --git a/src/UI/Popup/MarkAsFavourite.svelte b/src/UI/Popup/MarkAsFavourite.svelte new file mode 100644 index 000000000..394e4a1c3 --- /dev/null +++ b/src/UI/Popup/MarkAsFavourite.svelte @@ -0,0 +1,48 @@ + + + +{#if $isFavourite} +
+ markFavourite(false)} /> +
+ +
+
+ +{:else} +
+ markFavourite(true)} /> + +
+{/if} +
diff --git a/src/UI/Popup/MarkAsFavouriteMini.svelte b/src/UI/Popup/MarkAsFavouriteMini.svelte new file mode 100644 index 000000000..b8d242aac --- /dev/null +++ b/src/UI/Popup/MarkAsFavouriteMini.svelte @@ -0,0 +1,36 @@ + + + + {#if $isFavourite} + + {:else} + + {/if} + diff --git a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte index eaf9707a5..242f206e7 100644 --- a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte @@ -6,6 +6,7 @@ import { UIEventSource } from "../../../Logic/UIEventSource" import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import { twJoin } from "tailwind-merge" + import Icon from "../../Map/Icon.svelte"; export let selectedElement: Feature export let tags: UIEventSource> @@ -28,12 +29,7 @@ {#if mapping.icon !== undefined}
- +
{:else if mapping.then !== undefined} diff --git a/src/UI/SpecialVisualization.ts b/src/UI/SpecialVisualization.ts index 28125837c..5fd4f9fce 100644 --- a/src/UI/SpecialVisualization.ts +++ b/src/UI/SpecialVisualization.ts @@ -17,6 +17,7 @@ import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader" import { RasterLayerPolygon } from "../Models/RasterLayers" import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager" import { OsmTags } from "../Models/OsmFeature" +import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource" /** * The state needed to render a special Visualisation. @@ -33,7 +34,6 @@ export interface SpecialVisualizationState { } readonly indexedFeatures: IndexedFeatureSource - /** * Some features will create a new element that should be displayed. * These can be injected by appending them to this featuresource (and pinging it) @@ -59,6 +59,8 @@ export interface SpecialVisualizationState { readonly selectedLayer: UIEventSource readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }> + readonly favourites: FavouritesFeatureSource + /** * If data is currently being fetched from external sources */ diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index f32f28d9e..d2da94d4b 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -79,6 +79,8 @@ import ThemeViewState from "../Models/ThemeViewState" import LanguagePicker from "./InputElement/LanguagePicker.svelte" import LogoutButton from "./Base/LogoutButton.svelte" import OpenJosm from "./Base/OpenJosm.svelte" +import MarkAsFavourite from "./Popup/MarkAsFavourite.svelte" +import MarkAsFavouriteMini from "./Popup/MarkAsFavouriteMini.svelte" class NearbyImageVis implements SpecialVisualization { // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests @@ -1481,7 +1483,7 @@ export default class SpecialVisualizations { const tags = (( state )).geolocation.currentUserLocation.features.map( - (features) => features[0].properties + (features) => features[0]?.properties ) return new SvelteUIElement(AllTagsPanel, { state, @@ -1489,6 +1491,46 @@ export default class SpecialVisualizations { }) }, }, + { + funcName: "favourite_status", + needsUrls: [], + docs: "A button that allows a (logged in) contributor to mark a location as a favourite location", + args: [], + constr( + state: SpecialVisualizationState, + tagSource: UIEventSource>, + argument: string[], + feature: Feature, + layer: LayerConfig + ): BaseUIElement { + return new SvelteUIElement(MarkAsFavourite, { + tags: tagSource, + state, + layer, + feature, + }) + }, + }, + { + funcName: "favourite_icon", + needsUrls: [], + docs: "A small button that allows a (logged in) contributor to mark a location as a favourite location, sized to fit a title-icon", + args: [], + constr( + state: SpecialVisualizationState, + tagSource: UIEventSource>, + argument: string[], + feature: Feature, + layer: LayerConfig + ): BaseUIElement { + return new SvelteUIElement(MarkAsFavouriteMini, { + tags: tagSource, + state, + layer, + feature, + }) + }, + }, ] specialVisualizations.push(new AutoApplyButton(specialVisualizations)) diff --git a/src/UI/Test.svelte b/src/UI/Test.svelte index 47b2ce975..7103dc25e 100644 --- a/src/UI/Test.svelte +++ b/src/UI/Test.svelte @@ -1,11 +1,16 @@ - + + diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index a3b81e559..0db04b1f8 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -76,7 +76,6 @@ let showCrosshair = state.userRelatedState.showCrosshair; let arrowKeysWereUsed = state.mapProperties.lastKeyNavigation; let centerFeatures = state.closestFeatures.features; - $: console.log("Centerfeatures are", $centerFeatures) const selectedElementView = selectedElement.map( (selectedElement) => { // Svelte doesn't properly reload some of the legacy UI-elements @@ -232,7 +231,7 @@ - {#if $arrowKeysWereUsed !== undefined} + {#if $arrowKeysWereUsed !== undefined && $centerFeatures?.length > 0}
{#each $centerFeatures as feat, i (feat.properties.id)}
From 3ce21f61cb92f50c8ae90a97b7b090773f7f3e86 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 23 Nov 2023 17:06:30 +0100 Subject: [PATCH 04/99] Favourites: stabilize preferences and adding/removing favourites --- .../Sources/FavouritesFeatureSource.ts | 95 +++++++++++-------- src/Logic/Osm/OsmPreferences.ts | 33 ++++++- src/Logic/State/UserRelatedState.ts | 11 ++- src/Logic/Web/MangroveReviews.ts | 2 +- src/UI/Map/DynamicMarker.svelte | 2 +- src/UI/Map/Icon.svelte | 4 +- src/Utils.ts | 6 +- .../Conversion/PrepareTheme.spec.ts | 16 +++- 8 files changed, 122 insertions(+), 47 deletions(-) diff --git a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts index 4589d9493..bd6d52b4d 100644 --- a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts @@ -1,6 +1,6 @@ import StaticFeatureSource from "./StaticFeatureSource" import { Feature } from "geojson" -import { Store, UIEventSource } from "../../UIEventSource" +import { Store, Stores, UIEventSource } from "../../UIEventSource" import { OsmConnection } from "../../Osm/OsmConnection" import { OsmId } from "../../../Models/OsmFeature" import { GeoOperations } from "../../GeoOperations" @@ -14,6 +14,7 @@ import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" export default class FavouritesFeatureSource extends StaticFeatureSource { public static readonly prefix = "mapcomplete-favourite-" private readonly _osmConnection: OsmConnection + private readonly _detectedIds: Store constructor( connection: OsmConnection, @@ -21,62 +22,78 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { allFeatures: IndexedFeatureSource, layout: LayoutConfig ) { - const detectedIds = new UIEventSource>(undefined) - const features: Store = connection.preferencesHandler.preferences.map( - (prefs) => { + const features: Store = Stores.ListStabilized( + connection.preferencesHandler.preferences.map((prefs) => { const feats: Feature[] = [] const allIds = new Set() for (const key in prefs) { if (!key.startsWith(FavouritesFeatureSource.prefix)) { continue } - const id = key.substring(FavouritesFeatureSource.prefix.length) - const osmId = id.replace("-", "/") - if (id.indexOf("-property-") > 0 || id.indexOf("-layer") > 0) { - continue + + try { + const feat = FavouritesFeatureSource.ExtractFavourite(key, prefs) + if (!feat) { + continue + } + feats.push(feat) + allIds.add(feat.properties.id) + } catch (e) { + console.error("Could not create favourite from", key, "due to", e) } - allIds.add(osmId) - const geometry = <[number, number]>JSON.parse(prefs[key]) - const properties = FavouritesFeatureSource.getPropertiesFor(connection, id) - properties._orig_layer = prefs[FavouritesFeatureSource.prefix + id + "-layer"] - if (layout.layers.some((l) => l.id === properties._orig_layer)) { - continue - } - properties.id = osmId - properties._favourite = "yes" - feats.push({ - type: "Feature", - properties, - geometry: { - type: "Point", - coordinates: geometry, - }, - }) } - console.log("Favouritess are", feats) - detectedIds.setData(allIds) return feats - } + }) ) - super(features) + const featuresWithoutAlreadyPresent = features.map((features) => + features.filter( + (feat) => !layout.layers.some((l) => l.id === feat.properties._orig_layer) + ) + ) + + super(featuresWithoutAlreadyPresent) this._osmConnection = connection - detectedIds.addCallbackAndRunD((detected) => + this._detectedIds = Stores.ListStabilized( + features.map((feats) => feats.map((f) => f.properties.id)) + ) + this._detectedIds.addCallbackAndRunD((detected) => this.markFeatures(detected, indexedSource, allFeatures) ) // We use the indexedFeatureSource as signal to update allFeatures.features.map((_) => - this.markFeatures(detectedIds.data, indexedSource, allFeatures) + this.markFeatures(this._detectedIds.data, indexedSource, allFeatures) ) } + private static ExtractFavourite(key: string, prefs: Record): Feature { + const id = key.substring(FavouritesFeatureSource.prefix.length) + const osmId = id.replace("-", "/") + if (id.indexOf("-property-") > 0 || id.endsWith("-layer") || id.endsWith("-theme")) { + return undefined + } + const geometry = <[number, number]>JSON.parse(prefs[key]) + const properties = FavouritesFeatureSource.getPropertiesFor(prefs, id) + properties._orig_layer = prefs[FavouritesFeatureSource.prefix + id + "-layer"] + + properties.id = osmId + properties._favourite = "yes" + return { + type: "Feature", + properties, + geometry: { + type: "Point", + coordinates: geometry, + }, + } + } + private static getPropertiesFor( - osmConnection: OsmConnection, + prefs: Record, id: string ): Record { const properties: Record = {} - const prefs = osmConnection.preferencesHandler.preferences.data const minLength = FavouritesFeatureSource.prefix.length + id.length + "-property-".length for (const key in prefs) { if (key.length < minLength) { @@ -104,14 +121,18 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { if (isFavourite) { const center = GeoOperations.centerpointCoordinates(feature) pref.setData(JSON.stringify(center)) + this._osmConnection.GetPreference("favourite-" + id + "-layer").setData(layer) this._osmConnection.GetPreference("favourite-" + id + "-theme").setData(theme) - for (const key in tags.data) { const pref = this._osmConnection.GetPreference( "favourite-" + id + "-property-" + key.replaceAll(":", "__") ) - pref.setData(tags.data[key]) + const v = tags.data[key] + if (v === "" || !v) { + continue + } + pref.setData("" + v) } } else { this._osmConnection.preferencesHandler.removeAllWithPrefix( @@ -129,7 +150,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { } private markFeatures( - detected: Set, + detected: string[], featureProperties: FeaturePropertiesStore, allFeatures: IndexedFeatureSource ) { @@ -141,7 +162,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { } const store = featureProperties.getStore(id) const origValue = store.data._favourite - if (detected.has(id)) { + if (detected.indexOf(id) >= 0) { if (origValue !== "yes") { store.data._favourite = "yes" store.ping() diff --git a/src/Logic/Osm/OsmPreferences.ts b/src/Logic/Osm/OsmPreferences.ts index e36536258..1035dec82 100644 --- a/src/Logic/Osm/OsmPreferences.ts +++ b/src/Logic/Osm/OsmPreferences.ts @@ -12,6 +12,10 @@ export class OsmPreferences { "all-osm-preferences", {} ) + /** + * A map containing the individual preference sources + * @private + */ private readonly preferenceSources = new Map>() private auth: any private userDetails: UIEventSource @@ -21,7 +25,10 @@ export class OsmPreferences { this.auth = auth this.userDetails = osmConnection.userDetails const self = this - osmConnection.OnLoggedIn(() => self.UpdatePreferences()) + osmConnection.OnLoggedIn(() => { + self.UpdatePreferences(true) + return true + }) } /** @@ -72,11 +79,19 @@ export class OsmPreferences { let i = 0 while (str !== "") { if (str === undefined || str === "undefined") { + source.setData(undefined) throw ( "Got 'undefined' or a literal string containing 'undefined' for a long preference with name " + key ) } + if (str === "undefined") { + source.setData(undefined) + throw ( + "Got a literal string containing 'undefined' for a long preference with name " + + key + ) + } if (i > 100) { throw "This long preference is getting very long... " } @@ -197,7 +212,7 @@ export class OsmPreferences { }) } - private UpdatePreferences() { + private UpdatePreferences(forceUpdate?: boolean) { const self = this this.auth.xhr( { @@ -210,11 +225,22 @@ export class OsmPreferences { return } const prefs = value.getElementsByTagName("preference") + const seenKeys = new Set() for (let i = 0; i < prefs.length; i++) { const pref = prefs[i] const k = pref.getAttribute("k") const v = pref.getAttribute("v") self.preferences.data[k] = v + seenKeys.add(k) + } + if (forceUpdate) { + for (let key in self.preferences.data) { + if (seenKeys.has(key)) { + continue + } + console.log("Deleting key", key, "as we didn't find it upstream") + delete self.preferences.data[key] + } } // We merge all the preferences: new keys are uploaded @@ -289,9 +315,10 @@ export class OsmPreferences { removeAllWithPrefix(prefix: string) { for (const key in this.preferences.data) { if (key.startsWith(prefix)) { - this.GetPreference(key, undefined, { prefix: "" }).setData(undefined) + this.GetPreference(key, "", { prefix: "" }).setData(undefined) console.log("Clearing preference", key) } } + this.preferences.ping() } } diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index f38f32bad..bbc7c9f8c 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -294,6 +294,9 @@ export default class UserRelatedState { osmConnection.preferencesHandler.preferences.addCallback((newPrefs) => { for (const k in newPrefs) { const v = newPrefs[k] + if (v === "undefined" || !v) { + continue + } if (k.endsWith("-combined-length")) { const l = Number(v) const key = k.substring(0, k.length - "length".length) @@ -308,7 +311,6 @@ export default class UserRelatedState { } amendedPrefs.ping() - console.log("Amended prefs are:", amendedPrefs.data) }) const translationMode = osmConnection.GetPreference("translation-mode") @@ -395,6 +397,13 @@ export default class UserRelatedState { } if (tags[key + "-combined-0"]) { // A combined value exists + console.log( + "Trying to get a long preference for ", + key, + "with length value", + tags[key], + "as -combined-0 exists" + ) this.osmConnection.GetLongPreference(key, "").setData(tags[key]) } else { this.osmConnection diff --git a/src/Logic/Web/MangroveReviews.ts b/src/Logic/Web/MangroveReviews.ts index 19e2228d4..8bcfe3807 100644 --- a/src/Logic/Web/MangroveReviews.ts +++ b/src/Logic/Web/MangroveReviews.ts @@ -14,7 +14,7 @@ export class MangroveIdentity { const keypairEventSource = new UIEventSource(undefined) this.keypair = keypairEventSource mangroveIdentity.addCallbackAndRunD(async (data) => { - if (data === "") { + if (!data) { return } const keypair = await MangroveReviews.jwkToKeypair(JSON.parse(data)) diff --git a/src/UI/Map/DynamicMarker.svelte b/src/UI/Map/DynamicMarker.svelte index 609fbda60..a332cda0e 100644 --- a/src/UI/Map/DynamicMarker.svelte +++ b/src/UI/Map/DynamicMarker.svelte @@ -8,7 +8,7 @@ * Renders a 'marker', which consists of multiple 'icons' */ export let marker: IconConfig[] = config?.marker; - export let rotation: TagRenderingConfig; + export let rotation: TagRenderingConfig = undefined; export let tags: Store>; let _rotation = rotation ? tags.map(tags => rotation.GetRenderValue(tags).Subs(tags).txt) : new ImmutableStore(0); diff --git a/src/UI/Map/Icon.svelte b/src/UI/Map/Icon.svelte index a6a49eb52..dc8783494 100644 --- a/src/UI/Map/Icon.svelte +++ b/src/UI/Map/Icon.svelte @@ -32,8 +32,8 @@ */ export let icon: string | undefined; - export let color: string | undefined; - export let clss: string | undefined + export let color: string | undefined = undefined + export let clss: string | undefined = undefined {#if icon} diff --git a/src/Utils.ts b/src/Utils.ts index c89e4a468..7c5c67012 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -301,10 +301,14 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be if (str === undefined || str === null) { return undefined } + if (typeof str !== "string") { + console.error("Not a string:", str) + return undefined + } if (str.length <= l) { return str } - return str.substr(0, l - 3) + "..." + return str.substr(0, l - 1) + "…" } /** diff --git a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts index f6ab8d60a..009c9f08a 100644 --- a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts +++ b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts @@ -125,7 +125,21 @@ describe("PrepareTheme", () => { en: "Test layer - please ignore", }, titleIcons: [], - pointRendering: [{ location: ["point"], label: "xyz" }], + pointRendering: [ + { + location: ["point"], + label: "xyz", + iconBadges: [ + { + if: "_favourite=yes", + then: { + id: "circlewhiteheartred", + render: "circle:white;heart:red", + }, + }, + ], + }, + ], lineRendering: [{ width: 1 }], } const sharedLayers = constructSharedLayers() From 9fabab3588a7cdc3d04bcbae19b6868694bbc95f Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 02:17:14 +0100 Subject: [PATCH 05/99] Themes: add more questions about drinking water --- assets/layers/drinking_water/bottle.svg | 18 +++++ .../layers/drinking_water/bottle.svg.license | 2 + assets/layers/drinking_water/bubbler.svg | 18 +++++ .../layers/drinking_water/bubbler.svg.license | 2 + .../layers/drinking_water/drinking_water.json | 81 ++++++++++++++++++- .../layers/drinking_water/license_info.json | 30 +++++++ assets/layers/drinking_water/tap.svg | 73 +++++++++++++++++ assets/layers/drinking_water/tap.svg.license | 2 + assets/svg/license_info.json | 18 ----- 9 files changed, 224 insertions(+), 20 deletions(-) create mode 100644 assets/layers/drinking_water/bottle.svg create mode 100644 assets/layers/drinking_water/bottle.svg.license create mode 100644 assets/layers/drinking_water/bubbler.svg create mode 100644 assets/layers/drinking_water/bubbler.svg.license create mode 100644 assets/layers/drinking_water/tap.svg create mode 100644 assets/layers/drinking_water/tap.svg.license diff --git a/assets/layers/drinking_water/bottle.svg b/assets/layers/drinking_water/bottle.svg new file mode 100644 index 000000000..2f8217692 --- /dev/null +++ b/assets/layers/drinking_water/bottle.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/assets/layers/drinking_water/bottle.svg.license b/assets/layers/drinking_water/bottle.svg.license new file mode 100644 index 000000000..8e8b5805d --- /dev/null +++ b/assets/layers/drinking_water/bottle.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Unkown +SPDX-License-Identifier: CC0 \ No newline at end of file diff --git a/assets/layers/drinking_water/bubbler.svg b/assets/layers/drinking_water/bubbler.svg new file mode 100644 index 000000000..e0d30f29f --- /dev/null +++ b/assets/layers/drinking_water/bubbler.svg @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/assets/layers/drinking_water/bubbler.svg.license b/assets/layers/drinking_water/bubbler.svg.license new file mode 100644 index 000000000..c44973d7b --- /dev/null +++ b/assets/layers/drinking_water/bubbler.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: AIGA +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 23dd623aa..796c8628d 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -30,7 +30,8 @@ { "or": [ "amenity=drinking_water", - "drinking_water=yes" + "drinking_water=yes", + "disused:amenity=drinking_water" ] }, "man_made!=reservoir_covered", @@ -68,7 +69,8 @@ "if": { "or": [ "operational_status=broken", - "operational_status=closed" + "operational_status=closed", + "disused:amenity=drinking_water" ] }, "then": "close:#c33" @@ -147,6 +149,7 @@ "mappings": [ { "if": "operational_status=", + "addExtraTags": ["disused:amenity=","amenity=drinking_water"], "then": { "en": "This drinking water works", "nl": "Deze drinkwaterfontein werkt", @@ -190,6 +193,46 @@ ], "id": "Still in use?" }, + { + "id": "type", + "question": { + "en": "What type of drinking water point is this?", + "nl": "Wat voor soort drinkwaterpunt is dit?" + }, + "mappings": [ + { + "if": "fountain=bubbler", + "icon": "./assets/layers/drinking_water/bubbler.svg", + "then": { + "en": "This is a bubbler fountain. A water jet to drink from is sent upwards, typically controlled by a push button." + }, + "addExtraTags": [ + "man_made=" + ] + }, + { + "if": "fountain=bottle_refill", + "icon": "./assets/layers/drinking_water/bottle.svg", + "then": { + "en": "This is a bottle refill point where the water is sent downwards, typically controlled by a push button or a motion sensor. Drinking directly from the stream might be very hard or impossible." + }, + "addExtraTags": [ + "man_made=", + "bottle=yes" + ] + }, + { + "if": "man_made=water_tap", + "icon": "./assets/layers/drinking_water/tap.svg", + "then": { + "en": "This is a water tap. The water flows downward and the stream is controlled by a valve or push-button." + }, + "addExtraTags": [ + "fountain=" + ] + } + ] + }, { "question": { "en": "How easy is it to fill water bottles?", @@ -235,8 +278,29 @@ } } ], + "condition": "fountain!=bottle_refill", "id": "Bottle refill" }, + { + "id": "fee", + "question": { + "en": "Is this drinking water point free to use?" + }, + "mappings": [ + { + "if": "fee=no", + "then": { + "en": "Free to use" + } + }, + { + "if": "fee=yes", + "then": { + "en":"One needs to pay to use this drinking water point" + } + } + ] + }, { "id": "render-closest-drinking-water", "render": { @@ -293,6 +357,19 @@ "ca": "Es tracta d'una aixeta d'aigua o bomba d'aigua amb aigua no potable.
Per exemple les aixetes d'aigua amb aigua de pluja per aprofitar i regar les plantes properes
", "cs": "Jedná se o vodovodní kohoutek nebo vodní čerpadlo s nepitnou vodou.
Příkladem jsou vodovodní kohoutky s dešťovou vodou pro zalévání rostlin v okolí
" } + }, + { + "if": { + "and": [ + "amenity=", + "man_made=pump", + "historic=yes", + "drinking_water=no" + ] + }, + "then": { + "en":"This is a historic, manual water pump where no drinking water can be found" + } } ] }, diff --git a/assets/layers/drinking_water/license_info.json b/assets/layers/drinking_water/license_info.json index 343f5d945..ce8217e97 100644 --- a/assets/layers/drinking_water/license_info.json +++ b/assets/layers/drinking_water/license_info.json @@ -1,4 +1,24 @@ [ + { + "path": "bottle.svg", + "license": "CC0-1.0", + "authors": [ + "Unkown" + ], + "sources": [ + "https://www.svgrepo.com/svg/83123/water-bottle" + ] + }, + { + "path": "bubbler.svg", + "license": "CC0-1.0", + "authors": [ + "AIGA" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Drinking_Fountain_-_The_Noun_Project.svg" + ] + }, { "path": "drips.svg", "license": "CC-BY-SA-4.0", @@ -12,5 +32,15 @@ "sources": [ "https://osoc.be/editions/2020/cyclofix" ] + }, + { + "path": "tap.svg", + "license": "CC0-1.0", + "authors": [ + "Krzysztof Franek" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Water_DIN-style.svg" + ] } ] \ No newline at end of file diff --git a/assets/layers/drinking_water/tap.svg b/assets/layers/drinking_water/tap.svg new file mode 100644 index 000000000..b2459bfb9 --- /dev/null +++ b/assets/layers/drinking_water/tap.svg @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/assets/layers/drinking_water/tap.svg.license b/assets/layers/drinking_water/tap.svg.license new file mode 100644 index 000000000..c27ed8630 --- /dev/null +++ b/assets/layers/drinking_water/tap.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Krzysztof Franek +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 8a9e84cc7..d6ea4605a 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -859,24 +859,6 @@ ], "sources": [] }, - { - "path": "no_checkmark.svg", - "license": "TRIVIAL", - "authors": [], - "sources": [] - }, - { - "path": "no_checkmark.svg", - "license": "TRIVIAL", - "authors": [], - "sources": [] - }, - { - "path": "none.svg", - "license": "TRIVIAL", - "authors": [], - "sources": [] - }, { "path": "not_found.svg", "license": "CC-BY-4.0", From da68d365feab19a94ea85b2a756e3336bfb8b127 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 02:22:01 +0100 Subject: [PATCH 06/99] Themes: enable snapping for facade gardens --- assets/themes/facadegardens/facadegardens.json | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/themes/facadegardens/facadegardens.json b/assets/themes/facadegardens/facadegardens.json index c8aa40ba3..03bc83229 100644 --- a/assets/themes/facadegardens/facadegardens.json +++ b/assets/themes/facadegardens/facadegardens.json @@ -542,6 +542,7 @@ "leisure=garden", "garden:type=facade_garden" ], + "snapToLayer":["walls_and_buildings"], "title": { "nl": "een geveltuintje", "en": "a facade garden", From 550c60ab7f32e7f397de708d22d3fbbdbbe4eee3 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 02:51:25 +0100 Subject: [PATCH 07/99] Docs: update 'make your own theme'-page --- Docs/Making_Your_Own_Theme.md | 49 ++------- Docs/theme-template.json | 187 ---------------------------------- 2 files changed, 6 insertions(+), 230 deletions(-) delete mode 100644 Docs/theme-template.json diff --git a/Docs/Making_Your_Own_Theme.md b/Docs/Making_Your_Own_Theme.md index 10faf35fc..6483f4963 100644 --- a/Docs/Making_Your_Own_Theme.md +++ b/Docs/Making_Your_Own_Theme.md @@ -24,6 +24,11 @@ Please, do reach out to the MapComplete community channel on [Telegram](https://t.me/MapComplete) or [Matrix](https://app.element.io/#/room/#MapComplete:matrix.org). +Get started +----------- + +You can create your own theme at https://mapcomplete.org/studio + What is a good theme? --------------------- @@ -227,49 +232,7 @@ The entire tagRendering will thus be: ``` -The template ------------- - -[A basic template is available here](https://github.com/pietervdvn/MapComplete/blob/develop/Docs/theme-template.json). - -The custom theme generator --------------------------- - -The custom theme generator is a special page of MapComplete, where one can create their own theme. It makes it easier to -get started. - -However, the custom theme generator is extremely buggy and built before some updates. This means that some features -are _not_ available through the custom theme generator. The custom theme generator is good to get the basics of the -theme set up, but you will have to edit the raw JSON file anyway afterwards. - -[A quick tutorial for the custom theme generator can be found here](https://www.youtube.com/watch?v=nVbFrNVPxPw). - -Loading your theme ------------------- - -If you have your JSON file, there are three ways to distribute your theme: - -### a. base64 the JSON file - -Take the entire JSON file and [base64](https://www.base64encode.org/) encode it. - -Then open up the URL `https://mapcomplete.org?userlayout=true#`. - -Yes, this URL will be huge; and updates are difficult to distribute as you have to send a new URL to everyone. - -This is however excellent to have a 'quick and dirty' test version up and running as these links can be generated from the customThemeGenerator and can be quickly shared with a few other contributors. - -You can use the community maintained [ThemeHelper](https://github.com/tordans/MapComplete-ThemeHelper) to make this process easier. This uses `lzString.compressToBase64` which is the counterpart to how MapComplete decompresses the base64 input. - -### b. Host the JSON file - -Host the JSON file on a publicly accessible webserver (e.g. GitHub) and open up `https://mapcomplete.org?userlayout=` - -_Gotcha:_ Make sure the server that hosts your JSON has liberal caching settings. Otherwise one version of the file might get cached in the users' browser cache for a long time and updates are not destributed for this user. - -### c. Make it official - -Get your theme included into the official MapComplete: +## Make it official Did you make an awesome theme that you want to share with the OpenStreetMap community? Have it included in the main application. This makes sure that: diff --git a/Docs/theme-template.json b/Docs/theme-template.json deleted file mode 100644 index aeb665890..000000000 --- a/Docs/theme-template.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "#1": "This JSON file is a small template to get you started developing a theme", - "#2": "All lines starting with '#' are comments and can be removed in the theme if you don't need the explanation anymore", - "#3": "Make sure to join our chat channel at https://app.element.io/#/room/#MapComplete:matrix.org for questions, sharing your theme, ...", - "#4": "To actually load your theme: on linux: run a local webserver (e.g. `webfsd`) and go to https://mapcomplete.org/theme?userlayout=http://127.0.0.1:8080/path-to-your-theme.json", - "#5": "If you don't know how to run a webserver: go to https://www.base64encode.org/ , copy paste this entire document in the 'encode' field and encode it;", - "#6": "Then, go to https://mapcomplete.org/theme?userlayout=true#your-base64-encoded-file", - "id": "template", - "credits": "Write your name here (or remove everything)", - "title": { - "en": "Title of your theme", - "#1": "You can add extra languages here (and in all translation blocks), but make sure 'en' is everywhere" - }, - "description": { - "en": "The welcome message goes here" - }, - "icon": "/path/to/icon.svg OR path to an online svg, such as https://upload.wikimedia.org/wikipedia/commons/9/9f/Missing_Maps_Icon.svg", - "startZoom": 0, - "startLat": 0, - "startLon": 0, - "#7": "For more options and configuration, see the documentation in LayoutConfig.json", - "#8": "`layers` is where most of the content will be. Either reuse an already existing layer by simply calling it's ID or define a whole new layer. An overview of builtin layers is at https://github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinLayers.md#normal-layers", - "layers": [ - { - "id": "a singular noun describing the feature, in english", - "source": { - "osmTags": { - "#1": "For a description on which tags are possible, see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md", - "and": [ - "key0=value0", - "key1=value1", - { - "or": [ - "key2!=value3", - "key3=", - "key4~*", - "key5~some.[regex]*" - ] - } - ] - } - }, - "#4": "Minzoom: only download and show if zoom >= minzoom", - "minzoom": 12, - "name": { - "en": "Name of the layer, as shown in the layer selection" - }, - "title": { - "render": { - "en": "Title in a popup when a feature is clicked" - }, - "mappings": [ - { - "if": "name~*", - "then": { - "#1": "If name is given, use name instead as popup title. Note that the translation here uses '*' instead of 'en', which'll be shown in every language", - "*": "{name}" - } - } - ], - "#1": "Note that this is a tagRendering, but doesn't have a question field" - }, - "allowMove": true, - "deletion": { - "softDeletionTags": { - "and": [ - "razed:tourism=artwork", - "tourism=" - ] - }, - "neededChangesets": 5 - }, - "#2": "The maprenderings describe how a feature is shown on the map", - "mapRendering": [ - { - "#1": "Rendering block of a mapping which is shown for points AND at the center point of a line/area", - "location": [ - "point", - "centroid" - ], - "icon": "circle:white;URL or path to icon.svg", - "iconSize": "30,30,center", - "#2": "Note: all these values can be tagrenderings too, e.g.:", - "label": { - "render": { - "en": "Item" - }, - "mappings": [ - { - "if": "name~*", - "then": { - "*": "{name}" - } - } - ] - } - }, - { - "#1": "Rendering of a line", - "color": "#ff0", - "width": 5 - } - ], - "#3": "Presets describe which new items can be added on click. Delete this block if adding a new point is not relevant", - "presets": [ - { - "title": { - "en": "lowercase item" - }, - "tags": [ - "somekey=somevalue", - "otherkey=othervalue" - ], - "description": "A thorough definition of what the item is, usefull if people add stuff wrongly. This is optional", - "exampleImages": [ - "optionally add images here", - "an image.jpg", - "another example image of the feature.jpg" - ] - } - ], - "#1": "The tagrenderings are everything that must be shown and/or asked. Use a full tag-rendering section OR a single string to call a builtin tagrendering (see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinQuestions.md)", - "tagRenderings": [ - { - "render": { - "en": "This is a simple tagrendering without a question. It will always show this text as is" - } - }, - "images", - "website", - "phone", - "opening_hours", - "email", - "reviews", - { - "render": { - "en": "This is a simple tagrendering without a question. It will always show this text as is" - } - }, - { - "render": { - "en": "The value of some_osm_key is {some_osm_key} in this advanced tagrendering" - }, - "question": { - "en": "What is XYZ?" - }, - "freeform": { - "key": "some_osm_key", - "#1": "Types can be found at https://github.com/pietervdvn/MapComplete/blob/develop/Docs/SpecialInputElements.md", - "type": "nat" - }, - "mappings": [ - { - "if": "somekey=some_value", - "then": { - "en": "Text on radio button which also is shown if somekey=some_value is present on the object" - }, - "#1": "If this option is picked as answer, these tags will be added additionally. However, if 'somekey=some_value' is present, the above rendering will be shown", - "addExtraTags": [ - "extrakey=extravalue" - ] - } - ] - }, - { - "mappings": [ - { - "if": "somekey=some_value", - "then": { - "en": "Text on radio button which also is shown if somekey=some_value is present on the object" - }, - "icon": { - "path": "/path/to/extra-icon.svg OR url", - "class": "medium", - "#1": "An extra icon supporting this option" - }, - "#1": "If this option is picked as answer, these tags will be added additionally. However, if 'somekey=some_value' is present, the above rendering will be shown", - "addExtraTags": [ - "extrakey=extravalue" - ] - } - ] - } - ] - } - ] -} From b5627da624cf7c8296dd7d1ee74a2a52508738e5 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Fri, 3 Nov 2023 22:20:27 +0100 Subject: [PATCH 08/99] Show proposed routes/nodes,show route=hiking --- assets/themes/cyclenodes/cyclenodes.json | 70 +++++++++++++++----- assets/themes/walkingnodes/walkingnodes.json | 60 +++++++++++++---- langs/layers/en.json | 31 +++++++++ langs/layers/nl.json | 6 ++ langs/themes/ca.json | 11 ++- langs/themes/cs.json | 11 ++- langs/themes/da.json | 4 +- langs/themes/de.json | 17 +++-- langs/themes/en.json | 24 +++++-- langs/themes/es.json | 11 ++- langs/themes/fr.json | 11 ++- langs/themes/it.json | 4 +- langs/themes/nb_NO.json | 7 +- langs/themes/nl.json | 24 +++++-- langs/themes/pl.json | 11 ++- 15 files changed, 238 insertions(+), 64 deletions(-) diff --git a/assets/themes/cyclenodes/cyclenodes.json b/assets/themes/cyclenodes/cyclenodes.json index 2bb5eb2bb..8ecb092d6 100644 --- a/assets/themes/cyclenodes/cyclenodes.json +++ b/assets/themes/cyclenodes/cyclenodes.json @@ -112,7 +112,15 @@ "lineRendering": [ { "width": "4", - "color": "#00a703" + "color": { + "render": "#00a703", + "mappings": [ + { + "if": "state=proposed", + "then": "#f0a513" + } + ] + } } ], "pointRendering": null @@ -134,8 +142,9 @@ }, "source": { "osmTags": { - "and": [ - "rcn_ref~*" + "or": [ + "rcn_ref~*", + "proposed:rcn_ref~*" ] } }, @@ -146,14 +155,15 @@ "centroid" ], "label": { + "render": "
?
", "mappings": [ { "if": "rcn_ref~*", - "then": "
{rcn_ref}
" + "then": "
{rcn_ref}
" }, { - "if": "rcn_ref=", - "then": "
?
" + "if": "proposed:rcn_ref~*", + "then": "
{proposed:rcn_ref}
" } ] } @@ -162,16 +172,39 @@ "minzoom": 12, "title": { "render": { - "en": "Cycle node {rcn_ref}", - "de": "Fahrradknotenpunkt {rcn_ref}", - "es": "nodo ciclista {rcn_ref}", - "nb_NO": "sykkelnode {rcn_ref}", - "nl": "Fietsknooppunt {rcn_ref}", - "fr": "nœud cycliste {rcn_ref}", - "ca": "node ciclista {rcn_ref}", - "cs": "uzel cyklu {rcn_ref}", - "pl": "węzeł rowerowy {rcn_ref}" - } + "en": "Cycle node", + "de": "Fahrradknotenpunkt", + "es": "nodo ciclista", + "nb_NO": "sykkelnode", + "nl": "Fietsknooppunt", + "fr": "nœud cycliste", + "ca": "node ciclista", + "cs": "uzel cyklu", + "pl": "węzeł rowerowy" + }, + "mappings": [ + { + "if": "rcn_ref~*", + "then": { + "en": "Cycle node {rcn_ref}", + "de": "Fahrradknotenpunkt {rcn_ref}", + "es": "nodo ciclista {rcn_ref}", + "nb_NO": "sykkelnode {rcn_ref}", + "nl": "Fietsknooppunt {rcn_ref}", + "fr": "nœud cycliste {rcn_ref}", + "ca": "node ciclista {rcn_ref}", + "cs": "uzel cyklu {rcn_ref}", + "pl": "węzeł rowerowy {rcn_ref}" + } + }, + { + "if": "proposed:rcn_ref~*", + "then": { + "en": "Proposed cycle node {proposed:rcn_ref}", + "nl": "Voorgesteld fietsknooppunt {proposed:rcn_ref}" + } + } + ] }, "tagRenderings": [ { @@ -194,7 +227,8 @@ "en": "This cycling node has reference number {rcn_ref}", "nl": "Dit fietsknooppunt heeft referentienummer {rcn_ref}", "de": "Knotenpunktnummer {rcn_ref} des Fahrradknotenpunktnetzwerks" - } + }, + "condition": "rcn_ref~*" }, { "builtin": "survey_date", @@ -347,4 +381,4 @@ } } ] -} +} \ No newline at end of file diff --git a/assets/themes/walkingnodes/walkingnodes.json b/assets/themes/walkingnodes/walkingnodes.json index 3d08f5019..77fc07002 100644 --- a/assets/themes/walkingnodes/walkingnodes.json +++ b/assets/themes/walkingnodes/walkingnodes.json @@ -34,9 +34,14 @@ "source": { "osmTags": { "and": [ + { + "or": [ + "route=hiking", + "route=foot" + ] + }, "network=rwn", - "network:type=node_network", - "route=foot" + "network:type=node_network" ] } }, @@ -71,7 +76,15 @@ "lineRendering": [ { "width": "4", - "color": "#452b29" + "color": { + "render": "#452b29", + "mappings": [ + { + "if": "state=proposed", + "then": "#f0a513" + } + ] + } } ], "pointRendering": null, @@ -122,8 +135,9 @@ }, "source": { "osmTags": { - "and": [ - "rwn_ref~*" + "or": [ + "rwn_ref~*", + "proposed:rwn_ref~*" ] } }, @@ -134,14 +148,15 @@ "centroid" ], "label": { + "render": "
?
", "mappings": [ { "if": "rwn_ref~*", - "then": "
{rwn_ref}
" + "then": "
{rwn_ref}
" }, { - "if": "rwn_ref=", - "then": "
?
" + "if": "proposed:rwn_ref~*", + "then": "
{proposed:rwn_ref}
" } ] } @@ -150,10 +165,26 @@ "minzoom": 12, "title": { "render": { - "en": "Walking node {rwn_ref}", - "nl": "Wandelknooppunt {rwn_ref}", - "de": "Wanderknoten {rwn_ref}" - } + "en": "Walking node", + "nl": "Wandelknooppunt" + }, + "mappings": [ + { + "if": "rwn_ref~*", + "then": { + "en": "Walking node {rwn_ref}", + "nl": "Wandelknooppunt {rwn_ref}", + "de": "Wanderknoten {rwn_ref}" + } + }, + { + "if": "proposed:rwn_ref~*", + "then": { + "en": "Proposed walking node {proposed:rwn_ref}", + "nl": "Voorgesteld wandelknooppunt {proposed:rwn_ref}" + } + } + ] }, "tagRenderings": [ { @@ -176,7 +207,8 @@ "en": "This walking node has reference number {rwn_ref}", "nl": "Dit wandelknooppunt heeft referentienummer {rwn_ref}", "de": "Dieser Wanderknoten hat die Referenznummer {rwn_ref}" - } + }, + "condition": "rwn_ref~*" }, { "builtin": "survey_date", @@ -312,4 +344,4 @@ } } ] -} +} \ No newline at end of file diff --git a/langs/layers/en.json b/langs/layers/en.json index 0f2e3d6b5..4fdcba826 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4218,6 +4218,9 @@ }, "1": { "then": "This is a water tap or water pump with non-drinkable water.
Examples are water taps with rain water to tap water for nearby plants
" + }, + "2": { + "then": "This is a historic, manual water pump where no drinking water can be found" } } }, @@ -4256,8 +4259,33 @@ "question": "Is this drinking water spot still operational?", "render": "The operational status is {operational_status}" }, + "fee": { + "mappings": { + "0": { + "then": "Free to use" + }, + "1": { + "then": "One needs to pay to use this drinking water point" + } + }, + "question": "Is this drinking water point free to use?" + }, "render-closest-drinking-water": { "render": "There is another drinking water fountain at {_closest_other_drinking_water_distance} meters" + }, + "type": { + "mappings": { + "0": { + "then": "This is a bubbler fountain. A water jet to drink from is sent upwards, typically controlled by a push button." + }, + "1": { + "then": "This is a bottle refill point where the water is sent downwards, typically controlled by a push button or a motion sensor. Drinking directly from the stream might be very hard or impossible." + }, + "2": { + "then": "This is a water tap. The water flows downward and the stream is controlled by a valve or push-button." + } + }, + "question": "What type of drinking water point is this?" } }, "title": { @@ -8979,6 +9007,9 @@ }, "4": { "then": "The surface is concrete" + }, + "5": { + "then": "The surface is fine gravel" } }, "question": "Which is the surface of this sport pitch?", diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 35f8706f0..5184c7223 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4094,6 +4094,9 @@ }, "render-closest-drinking-water": { "render": "Er bevindt zich een ander drinkwaterpunt op {_closest_other_drinking_water_distance} meter" + }, + "type": { + "question": "Wat voor soort drinkwaterpunt is dit?" } }, "title": { @@ -7927,6 +7930,9 @@ }, "4": { "then": "De ondergrond is beton" + }, + "5": { + "then": "De ondergrond bestaat uit grind" } }, "question": "Wat is de ondergrond van dit sportveld?", diff --git a/langs/themes/ca.json b/langs/themes/ca.json index 171590816..e1dd8e763 100644 --- a/langs/themes/ca.json +++ b/langs/themes/ca.json @@ -509,7 +509,12 @@ } }, "title": { - "render": "node ciclista {rcn_ref}" + "mappings": { + "0": { + "then": "node ciclista {rcn_ref}" + } + }, + "render": "node ciclista" } } }, @@ -1159,10 +1164,10 @@ "1": { "mappings": { "0": { - "then": "Sí, hi ha una vorera a aquest costat del carrer" + "then": "Hi ha una vorera a aquest costat del carrer" }, "1": { - "then": "No, no hi ha vorera per la que caminar" + "then": "No hi ha vorera per la que caminar" }, "2": { "then": "Hi ha una vorera mapejada separadament per on caminar" diff --git a/langs/themes/cs.json b/langs/themes/cs.json index f7fa4de1b..8c0e84a1c 100644 --- a/langs/themes/cs.json +++ b/langs/themes/cs.json @@ -509,7 +509,12 @@ } }, "title": { - "render": "uzel cyklu {rcn_ref}" + "mappings": { + "0": { + "then": "uzel cyklu {rcn_ref}" + } + }, + "render": "uzel cyklu" } } }, @@ -1163,10 +1168,10 @@ "1": { "mappings": { "0": { - "then": "Ano, na této straně silnice je chodník" + "then": "Na této straně silnice je chodník" }, "1": { - "then": "Ne, není tu žádný chodník" + "then": "Není tu žádný chodník" }, "2": { "then": "Na mapě je vyznačen samostatný chodník" diff --git a/langs/themes/da.json b/langs/themes/da.json index 73fdd6129..302dce5d0 100644 --- a/langs/themes/da.json +++ b/langs/themes/da.json @@ -806,10 +806,10 @@ "1": { "mappings": { "0": { - "then": "Ja, der er et fortov på denne side af vejen" + "then": "Der er et fortov på denne side af vejen" }, "1": { - "then": "Nej, der er ikke noget fortov at gå på" + "then": "Der er ikke noget fortov at gå på" }, "2": { "then": "Der er et særskilt kortlagt fortov at gå på" diff --git a/langs/themes/de.json b/langs/themes/de.json index cc768eb16..75aa2f5ad 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -524,7 +524,12 @@ } }, "title": { - "render": "Fahrradknotenpunkt {rcn_ref}" + "mappings": { + "0": { + "then": "Fahrradknotenpunkt {rcn_ref}" + } + }, + "render": "Fahrradknotenpunkt" } }, "2": { @@ -1199,10 +1204,10 @@ "1": { "mappings": { "0": { - "then": "Ja, es gibt einen Bürgersteig auf dieser Straßenseite" + "then": "Es gibt einen Bürgersteig auf dieser Straßenseite" }, "1": { - "then": "Nein, es gibt keinen Bürgersteig für Fußgänger" + "then": "Es gibt keinen Bürgersteig für Fußgänger" }, "2": { "then": "Es gibt einen separat kartierten Bürgersteig für Fußgänger" @@ -1422,7 +1427,11 @@ } }, "title": { - "render": "Wanderknoten {rwn_ref}" + "mappings": { + "0": { + "then": "Wanderknoten {rwn_ref}" + } + } } }, "2": { diff --git a/langs/themes/en.json b/langs/themes/en.json index 7d423c5de..5a01a4795 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -524,7 +524,15 @@ } }, "title": { - "render": "Cycle node {rcn_ref}" + "mappings": { + "0": { + "then": "Cycle node {rcn_ref}" + }, + "1": { + "then": "Proposed cycle node {proposed:rcn_ref}" + } + }, + "render": "Cycle node" } }, "2": { @@ -1199,10 +1207,10 @@ "1": { "mappings": { "0": { - "then": "Yes, there is a sidewalk on this side of the road" + "then": "There is a sidewalk on this side of the road" }, "1": { - "then": "No, there is no sidewalk to walk on" + "then": "There is no sidewalk to walk on" }, "2": { "then": "There is a separately mapped sidewalk to walk on" @@ -1422,7 +1430,15 @@ } }, "title": { - "render": "Walking node {rwn_ref}" + "mappings": { + "0": { + "then": "Walking node {rwn_ref}" + }, + "1": { + "then": "Proposed walking node {proposed:rwn_ref}" + } + }, + "render": "Walking node" } }, "2": { diff --git a/langs/themes/es.json b/langs/themes/es.json index 45cf01b25..cc5186749 100644 --- a/langs/themes/es.json +++ b/langs/themes/es.json @@ -509,7 +509,12 @@ } }, "title": { - "render": "nodo ciclista {rcn_ref}" + "mappings": { + "0": { + "then": "nodo ciclista {rcn_ref}" + } + }, + "render": "nodo ciclista" } } }, @@ -1163,10 +1168,10 @@ "1": { "mappings": { "0": { - "then": "Sí, hay una acera en este lado de la calle" + "then": "Hay una acera en este lado de la calle" }, "1": { - "then": "No, no hay acera por la que caminar" + "then": "No hay acera por la que caminar" }, "2": { "then": "Hay una acera mapeada por separado por la que caminar" diff --git a/langs/themes/fr.json b/langs/themes/fr.json index 38dbc4d73..371633038 100644 --- a/langs/themes/fr.json +++ b/langs/themes/fr.json @@ -506,7 +506,12 @@ } }, "title": { - "render": "nœud cycliste {rcn_ref}" + "mappings": { + "0": { + "then": "nœud cycliste {rcn_ref}" + } + }, + "render": "nœud cycliste" } } }, @@ -1102,10 +1107,10 @@ "1": { "mappings": { "0": { - "then": "Oui, il y a un trottoir de ce côté de la route" + "then": "Il y a un trottoir de ce côté de la route" }, "1": { - "then": "Non, il n'y a pas de trottoir où marcher" + "then": "Il n'y a pas de trottoir où marcher" }, "2": { "then": "Il y a un trottoir où marcher cartographié séparément" diff --git a/langs/themes/it.json b/langs/themes/it.json index 45464a5dc..457e34574 100644 --- a/langs/themes/it.json +++ b/langs/themes/it.json @@ -599,10 +599,10 @@ "1": { "mappings": { "0": { - "then": "Sì, c'è un marciapiede su questo lato della strada" + "then": "C'è un marciapiede su questo lato della strada" }, "1": { - "then": "No, non c'è un marciapiede su cui camminare" + "then": "Non c'è un marciapiede su cui camminare" } } } diff --git a/langs/themes/nb_NO.json b/langs/themes/nb_NO.json index abc997dee..aff67e03c 100644 --- a/langs/themes/nb_NO.json +++ b/langs/themes/nb_NO.json @@ -283,7 +283,12 @@ "1": { "name": "noder", "title": { - "render": "sykkelnode {rcn_ref}" + "mappings": { + "0": { + "then": "sykkelnode {rcn_ref}" + } + }, + "render": "sykkelnode" } } }, diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 16e57a9b2..ecf3d12b3 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -475,7 +475,15 @@ } }, "title": { - "render": "Fietsknooppunt {rcn_ref}" + "mappings": { + "0": { + "then": "Fietsknooppunt {rcn_ref}" + }, + "1": { + "then": "Voorgesteld fietsknooppunt {proposed:rcn_ref}" + } + }, + "render": "Fietsknooppunt" } } }, @@ -1156,10 +1164,10 @@ "1": { "mappings": { "0": { - "then": "Ja, er is een stoep aan deze kant van de weg" + "then": "Er is een stoep aan deze kant van de weg" }, "1": { - "then": "Nee, er is geen stoep om op te lopen" + "then": "Er is geen stoep om op te lopen" }, "2": { "then": "Er is een apart ingetekende stoep om op te lopen" @@ -1424,7 +1432,15 @@ } }, "title": { - "render": "Wandelknooppunt {rwn_ref}" + "mappings": { + "0": { + "then": "Wandelknooppunt {rwn_ref}" + }, + "1": { + "then": "Voorgesteld wandelknooppunt {proposed:rwn_ref}" + } + }, + "render": "Wandelknooppunt" } } }, diff --git a/langs/themes/pl.json b/langs/themes/pl.json index 22eee941e..a8f2b1e2d 100644 --- a/langs/themes/pl.json +++ b/langs/themes/pl.json @@ -509,7 +509,12 @@ } }, "title": { - "render": "węzeł rowerowy {rcn_ref}" + "mappings": { + "0": { + "then": "węzeł rowerowy {rcn_ref}" + } + }, + "render": "węzeł rowerowy" } } }, @@ -1163,10 +1168,10 @@ "1": { "mappings": { "0": { - "then": "Tak, jest chodnik z boku drogi" + "then": "Jest chodnik z boku drogi" }, "1": { - "then": "Nie, nie ma chodnika, którym można chodzić" + "then": "Nie ma chodnika, którym można chodzić" }, "2": { "then": "Jest oddzielnie oznaczony chodnik" From 0f545b29cb91bb44b3d7c398dc4aaf312fb56786 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 12:21:46 +0100 Subject: [PATCH 09/99] UI: tweak icon location --- src/UI/Popup/TagRendering/TagRenderingMapping.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte index eaf9707a5..56d308681 100644 --- a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte @@ -27,7 +27,7 @@ {#if mapping.icon !== undefined} -
+
Date: Wed, 29 Nov 2023 14:29:11 +0100 Subject: [PATCH 10/99] Logic: enable to re-export tagsFilter as TagsConfig; improve optimization for comparingTag --- .../{favourite.json => favourite.proto.json} | 0 scripts/generateFavouritesLayer.ts | 25 +++++++ src/Logic/Tags/And.ts | 5 ++ src/Logic/Tags/ComparingTag.ts | 68 +++++++++++++++++-- src/Logic/Tags/Or.ts | 11 ++- src/Logic/Tags/RegexTag.ts | 5 ++ src/Logic/Tags/SubstitutingTag.ts | 5 ++ src/Logic/Tags/Tag.ts | 5 ++ src/Logic/Tags/TagUtils.ts | 24 +++---- src/Logic/Tags/TagsFilter.ts | 4 ++ src/UI/Favourites/FavouriteSummary.svelte | 0 src/UI/Favourites/Favourites.svelte | 8 +++ 12 files changed, 140 insertions(+), 20 deletions(-) rename assets/layers/favourite/{favourite.json => favourite.proto.json} (100%) create mode 100644 scripts/generateFavouritesLayer.ts create mode 100644 src/UI/Favourites/FavouriteSummary.svelte create mode 100644 src/UI/Favourites/Favourites.svelte diff --git a/assets/layers/favourite/favourite.json b/assets/layers/favourite/favourite.proto.json similarity index 100% rename from assets/layers/favourite/favourite.json rename to assets/layers/favourite/favourite.proto.json diff --git a/scripts/generateFavouritesLayer.ts b/scripts/generateFavouritesLayer.ts new file mode 100644 index 000000000..334742b45 --- /dev/null +++ b/scripts/generateFavouritesLayer.ts @@ -0,0 +1,25 @@ +import Script from "./Script" +import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" +import { readFileSync, writeFileSync } from "fs" +import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" + +class PrepareFavouritesLayerJson extends Script { + constructor() { + super("Prepares the 'favourites'-layer") + } + + async main(args: string[]): Promise { + const allConfigs = AllSharedLayers.getSharedLayersConfigs() + const proto = this.readLayer("favourite/favourite.proto.json") + const questions = allConfigs.get("questions") + proto.tagRenderings.push(...questions.tagRenderings) + + writeFileSync("./assets/layers/favourite/favourite.json", JSON.stringify(proto, null, " ")) + } + + private readLayer(path: string): LayerConfigJson { + return JSON.parse(readFileSync("./assets/layers/" + path, "utf8")) + } +} + +new PrepareFavouritesLayerJson().run() diff --git a/src/Logic/Tags/And.ts b/src/Logic/Tags/And.ts index 378518dd1..98da75ae0 100644 --- a/src/Logic/Tags/And.ts +++ b/src/Logic/Tags/And.ts @@ -3,6 +3,7 @@ import { Or } from "./Or" import { TagUtils } from "./TagUtils" import { Tag } from "./Tag" import { RegexTag } from "./RegexTag" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" export class And extends TagsFilter { public and: TagsFilter[] @@ -72,6 +73,10 @@ export class And extends TagsFilter { return allChoices } + asJson(): TagConfigJson { + return { and: this.and.map((a) => a.asJson()) } + } + asHumanString(linkToWiki: boolean, shorten: boolean, properties: Record) { return this.and .map((t) => { diff --git a/src/Logic/Tags/ComparingTag.ts b/src/Logic/Tags/ComparingTag.ts index 685cd2550..8009662f4 100644 --- a/src/Logic/Tags/ComparingTag.ts +++ b/src/Logic/Tags/ComparingTag.ts @@ -1,18 +1,23 @@ import { TagsFilter } from "./TagsFilter" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" +import { Tag } from "./Tag" export default class ComparingTag implements TagsFilter { private readonly _key: string private readonly _predicate: (value: string) => boolean - private readonly _representation: string + private readonly _representation: "<" | ">" | "<=" | ">=" + private readonly _boundary: string constructor( key: string, predicate: (value: string | undefined) => boolean, - representation: string = "" + representation: "<" | ">" | "<=" | ">=", + boundary: string ) { this._key = key this._predicate = predicate this._representation = representation + this._boundary = boundary } asChange(properties: Record): { k: string; v: string }[] { @@ -20,15 +25,64 @@ export default class ComparingTag implements TagsFilter { } asHumanString(linkToWiki: boolean, shorten: boolean, properties: Record) { - return this._key + this._representation + return this._key + this._representation + this._boundary } asOverpass(): string[] { throw "A comparable tag can not be used as overpass filter" } + /** + * const tg = new ComparingTag("key", value => (Number(value) < 42), "<", "42") + * const tg0 = new ComparingTag("key", value => (Number(value) < 42), "<", "42") + * const tg1 = new ComparingTag("key", value => (Number(value) <= 42), "<=", "42") + * const against = new ComparingTag("key", value => (Number(value) > 0), ">", "0") + * tg.shadows(new Tag("key", "41")) // => true + * tg.shadows(new Tag("key", "0")) // => true + * tg.shadows(new Tag("key", "43")) // => false + * tg.shadows(new Tag("key", "0")) // => true + * tg.shadows(tg) // => true + * tg.shadows(tg0) // => true + * tg.shadows(against) // => false + * tg1.shadows(tg0) // => true + * tg0.shadows(tg1) // => false + * + */ shadows(other: TagsFilter): boolean { - return other === this + if (other === this) { + return true + } + if (other instanceof ComparingTag) { + if (other._key !== this._key) { + return false + } + const selfDesc = this._representation === "<" || this._representation === "<=" + const otherDesc = other._representation === "<" || other._representation === "<=" + if (selfDesc !== otherDesc) { + return false + } + if ( + this._boundary === other._boundary && + this._representation === other._representation + ) { + return true + } + if (this._predicate(other._boundary)) { + return true + } + return false + } + + if (other instanceof Tag) { + if (other.key !== this._key) { + return false + } + if (this.matchesProperties({ [other.key]: other.value })) { + return true + } + } + + return false } isUsableAsAnswer(): boolean { @@ -38,7 +92,7 @@ export default class ComparingTag implements TagsFilter { /** * Checks if the properties match * - * const t = new ComparingTag("key", (x => Number(x) < 42)) + * const t = new ComparingTag("key", (x => Number(x) < 42), "<", "42") * t.matchesProperties({key: 42}) // => false * t.matchesProperties({key: 41}) // => true * t.matchesProperties({key: 0}) // => true @@ -56,6 +110,10 @@ export default class ComparingTag implements TagsFilter { return [] } + asJson(): TagConfigJson { + return this._key + this._representation + } + optimize(): TagsFilter | boolean { return this } diff --git a/src/Logic/Tags/Or.ts b/src/Logic/Tags/Or.ts index f7018c40b..da932049a 100644 --- a/src/Logic/Tags/Or.ts +++ b/src/Logic/Tags/Or.ts @@ -1,6 +1,7 @@ import { TagsFilter } from "./TagsFilter" import { TagUtils } from "./TagUtils" import { And } from "./And" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" export class Or extends TagsFilter { public or: TagsFilter[] @@ -27,6 +28,10 @@ export class Or extends TagsFilter { return false } + asJson(): TagConfigJson { + return { or: this.or.map((o) => o.asJson()) } + } + /** * * import {Tag} from "./Tag"; @@ -174,9 +179,9 @@ export class Or extends TagsFilter { const newOrs: TagsFilter[] = [] let containedAnds: And[] = [] for (const tf of optimized) { - if (tf instanceof Or) { + if (tf["or"]) { // expand all the nested ors... - newOrs.push(...tf.or) + newOrs.push(...tf["or"]) } else if (tf instanceof And) { // partition of all the ands containedAnds.push(tf) @@ -191,7 +196,7 @@ export class Or extends TagsFilter { const cleanedContainedANds: And[] = [] outer: for (let containedAnd of containedAnds) { for (const known of newOrs) { - // input for optimazation: (K=V | (X=Y & K=V)) + // input for optimization: (K=V | (X=Y & K=V)) // containedAnd: (X=Y & K=V) // newOrs (and thus known): (K=V) --> false const cleaned = containedAnd.removePhraseConsideredKnown(known, false) diff --git a/src/Logic/Tags/RegexTag.ts b/src/Logic/Tags/RegexTag.ts index e6486113a..d133c3663 100644 --- a/src/Logic/Tags/RegexTag.ts +++ b/src/Logic/Tags/RegexTag.ts @@ -1,5 +1,6 @@ import { Tag } from "./Tag" import { TagsFilter } from "./TagsFilter" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" export class RegexTag extends TagsFilter { public readonly key: RegExp | string @@ -82,6 +83,10 @@ export class RegexTag extends TagsFilter { } } + asJson(): TagConfigJson { + return this.asHumanString() + } + isUsableAsAnswer(): boolean { return false } diff --git a/src/Logic/Tags/SubstitutingTag.ts b/src/Logic/Tags/SubstitutingTag.ts index 7d5435a06..6e9d29311 100644 --- a/src/Logic/Tags/SubstitutingTag.ts +++ b/src/Logic/Tags/SubstitutingTag.ts @@ -1,6 +1,7 @@ import { TagsFilter } from "./TagsFilter" import { Tag } from "./Tag" import { Utils } from "../../Utils" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" /** * The substituting-tag uses the tags of a feature a variables and replaces them. @@ -45,6 +46,10 @@ export default class SubstitutingTag implements TagsFilter { ) } + asJson(): TagConfigJson { + return this._key + (this._invert ? "!" : "") + ":=" + this._value + } + asOverpass(): string[] { throw "A variable with substitution can not be used to query overpass" } diff --git a/src/Logic/Tags/Tag.ts b/src/Logic/Tags/Tag.ts index 7cb01a9d5..b532b7053 100644 --- a/src/Logic/Tags/Tag.ts +++ b/src/Logic/Tags/Tag.ts @@ -1,5 +1,6 @@ import { Utils } from "../../Utils" import { TagsFilter } from "./TagsFilter" +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" export class Tag extends TagsFilter { public key: string @@ -67,6 +68,10 @@ export class Tag extends TagsFilter { return [`["${this.key}"="${this.value}"]`] } + asJson(): TagConfigJson { + return this.key + "=" + this.value + } + /** const t = new Tag("key", "value") diff --git a/src/Logic/Tags/TagUtils.ts b/src/Logic/Tags/TagUtils.ts index adc862922..91d3a4ca6 100644 --- a/src/Logic/Tags/TagUtils.ts +++ b/src/Logic/Tags/TagUtils.ts @@ -15,13 +15,14 @@ type Tags = Record export type UploadableTag = Tag | SubstitutingTag | And export class TagUtils { - public static readonly comparators: ReadonlyArray<[string, (a: number, b: number) => boolean]> = - [ - ["<=", (a, b) => a <= b], - [">=", (a, b) => a >= b], - ["<", (a, b) => a < b], - [">", (a, b) => a > b], - ] + public static readonly comparators: ReadonlyArray< + ["<" | ">" | "<=" | ">=", (a: number, b: number) => boolean] + > = [ + ["<=", (a, b) => a <= b], + [">=", (a, b) => a >= b], + ["<", (a, b) => a < b], + [">", (a, b) => a > b], + ] public static modeDocumentation: Record< string, { name: string; docs: string; uploadable?: boolean; overpassSupport: boolean } @@ -735,11 +736,10 @@ export class TagUtils { const tag = json as string for (const [operator, comparator] of TagUtils.comparators) { if (tag.indexOf(operator) >= 0) { - const split = Utils.SplitFirst(tag, operator) - - let val = Number(split[1].trim()) + const split = Utils.SplitFirst(tag, operator).map((v) => v.trim()) + let val = Number(split[1]) if (isNaN(val)) { - val = new Date(split[1].trim()).getTime() + val = new Date(split[1]).getTime() } const f = (value: string | number | undefined) => { @@ -762,7 +762,7 @@ export class TagUtils { } return comparator(b, val) } - return new ComparingTag(split[0], f, operator + val) + return new ComparingTag(split[0], f, operator, "" + val) } } diff --git a/src/Logic/Tags/TagsFilter.ts b/src/Logic/Tags/TagsFilter.ts index b06158b4f..e925a76ef 100644 --- a/src/Logic/Tags/TagsFilter.ts +++ b/src/Logic/Tags/TagsFilter.ts @@ -1,3 +1,5 @@ +import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" + export abstract class TagsFilter { abstract asOverpass(): string[] @@ -17,6 +19,8 @@ export abstract class TagsFilter { properties: Record ): string + abstract asJson(): TagConfigJson + abstract usedKeys(): string[] /** diff --git a/src/UI/Favourites/FavouriteSummary.svelte b/src/UI/Favourites/FavouriteSummary.svelte new file mode 100644 index 000000000..e69de29bb diff --git a/src/UI/Favourites/Favourites.svelte b/src/UI/Favourites/Favourites.svelte new file mode 100644 index 000000000..ff6e0331f --- /dev/null +++ b/src/UI/Favourites/Favourites.svelte @@ -0,0 +1,8 @@ + From 2c662c957860144a927260504ca30795f9249238 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 17:05:45 +0100 Subject: [PATCH 11/99] Themes: add icons, add 'auto'-title-icons --- .../layers/drinking_water/bottle.svg.license | 2 +- .../layers/drinking_water/drinking_water.json | 75 +++++++++++++++++ .../layers/drinking_water/license_info.json | 16 ++++ assets/layers/drinking_water/no_winter.svg | 81 +++++++++++++++++++ .../drinking_water/no_winter.svg.license | 2 + assets/layers/drinking_water/winter.svg | 73 +++++++++++++++++ .../layers/drinking_water/winter.svg.license | 2 + src/Logic/State/UserSettingsMetaTagging.ts | 48 +++-------- .../ThemeConfig/Conversion/PrepareLayer.ts | 56 +++++++++++-- .../ThemeConfig/Json/LayerConfigJson.ts | 2 + 10 files changed, 313 insertions(+), 44 deletions(-) create mode 100644 assets/layers/drinking_water/no_winter.svg create mode 100644 assets/layers/drinking_water/no_winter.svg.license create mode 100644 assets/layers/drinking_water/winter.svg create mode 100644 assets/layers/drinking_water/winter.svg.license diff --git a/assets/layers/drinking_water/bottle.svg.license b/assets/layers/drinking_water/bottle.svg.license index 8e8b5805d..1480316c2 100644 --- a/assets/layers/drinking_water/bottle.svg.license +++ b/assets/layers/drinking_water/bottle.svg.license @@ -1,2 +1,2 @@ SPDX-FileCopyrightText: Unkown -SPDX-License-Identifier: CC0 \ No newline at end of file +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 796c8628d..ff9bdb5b9 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -62,6 +62,7 @@ "cs": "Pitná voda" } }, + "titleIcons": ["icons.defaults", "auto:type", "auto:seasonal"], "pointRendering": [ { "iconBadges": [ @@ -301,6 +302,79 @@ } ] }, + { + "id": "seasonal", + "question": { + "en": "Is this drinking water point available all year round?" + }, + "mappings": [ + { + "if": "seasonal=no", + "then":{ + "en":"This drinking water point is available all around the year" + } + }, + { + "if": "seasonal=summer", + "then":{ + "en":"This drinking water point is only available in summer" + } + }, + { + "if": "seasonal=spring;summer;autumn", + "icon": "./assets/layers/drinking_water/no_winter.svg", + "then":{ + "en":"This drinking water point is closed during the winter" + } + } + ] + }, + {"builtin":["opening_hours_24_7"], + "override": { + "questionHint":{ + "en":"These are the opening hours if the drinking water fountain is operational." + }, + "+mappings":[ + { + "if":{ + "and": [ + "seasonal!=no", + {"or":[ + { + "and":[ + "seasonal!~.*winter.*", + "_now:date~....-(12|01|02)-.." + ] + }, + { + "and":[ + "seasonal!~.*spring.*", + "_now:date~....-(03|04|05)-.." + ] + }, + { + "and":[ + "seasonal!~.*summer.*", + "_now:date~....-(06|07|08)-.." + ] + }, + { + "and":[ + "seasonal!~.*autumn.*", + "_now:date~....-(09|10|11)-.." + ] + } + ]} + ] + }, + "then":{ + "en": "This drinking water fountain is closed this season." + }, + "hideInAnswer":true + } + ] + } + }, { "id": "render-closest-drinking-water", "render": { @@ -316,6 +390,7 @@ }, "condition": "_closest_other_drinking_water_id~*" } + ], "deletion": { "softDeletionTags": { diff --git a/assets/layers/drinking_water/license_info.json b/assets/layers/drinking_water/license_info.json index ce8217e97..57460d021 100644 --- a/assets/layers/drinking_water/license_info.json +++ b/assets/layers/drinking_water/license_info.json @@ -33,6 +33,14 @@ "https://osoc.be/editions/2020/cyclofix" ] }, + { + "path": "no_winter.svg", + "license": "CC0-1.0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, { "path": "tap.svg", "license": "CC0-1.0", @@ -42,5 +50,13 @@ "sources": [ "https://commons.wikimedia.org/wiki/File:Water_DIN-style.svg" ] + }, + { + "path": "winter.svg", + "license": "CC0-1.0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] } ] \ No newline at end of file diff --git a/assets/layers/drinking_water/no_winter.svg b/assets/layers/drinking_water/no_winter.svg new file mode 100644 index 000000000..5e4766a58 --- /dev/null +++ b/assets/layers/drinking_water/no_winter.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/layers/drinking_water/no_winter.svg.license b/assets/layers/drinking_water/no_winter.svg.license new file mode 100644 index 000000000..ed0288300 --- /dev/null +++ b/assets/layers/drinking_water/no_winter.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Pieter Vander Vennet +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/drinking_water/winter.svg b/assets/layers/drinking_water/winter.svg new file mode 100644 index 000000000..f1c2df8b4 --- /dev/null +++ b/assets/layers/drinking_water/winter.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + diff --git a/assets/layers/drinking_water/winter.svg.license b/assets/layers/drinking_water/winter.svg.license new file mode 100644 index 000000000..ed0288300 --- /dev/null +++ b/assets/layers/drinking_water/winter.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Pieter Vander Vennet +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/src/Logic/State/UserSettingsMetaTagging.ts b/src/Logic/State/UserSettingsMetaTagging.ts index 6e568c5c3..33a5ae85b 100644 --- a/src/Logic/State/UserSettingsMetaTagging.ts +++ b/src/Logic/State/UserSettingsMetaTagging.ts @@ -1,42 +1,14 @@ import { Utils } from "../../Utils" /** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */ export class ThemeMetaTagging { - public static readonly themeName = "usersettings" + public static readonly themeName = "usersettings" - public metaTaggging_for_usersettings(feat: { properties: Record }) { - Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () => - feat.properties._description - .match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/) - ?.at(1) - ) - Utils.AddLazyProperty( - feat.properties, - "_d", - () => feat.properties._description?.replace(/</g, "<")?.replace(/>/g, ">") ?? "" - ) - Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () => - ((feat) => { - const e = document.createElement("div") - e.innerHTML = feat.properties._d - return Array.from(e.getElementsByTagName("a")).filter( - (a) => a.href.match(/mastodon|en.osm.town/) !== null - )[0]?.href - })(feat) - ) - Utils.AddLazyProperty(feat.properties, "_mastodon_link", () => - ((feat) => { - const e = document.createElement("div") - e.innerHTML = feat.properties._d - return Array.from(e.getElementsByTagName("a")).filter( - (a) => a.getAttribute("rel")?.indexOf("me") >= 0 - )[0]?.href - })(feat) - ) - Utils.AddLazyProperty( - feat.properties, - "_mastodon_candidate", - () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a - ) - feat.properties["__current_backgroun"] = "initial_value" - } -} + public metaTaggging_for_usersettings(feat: {properties: Record}) { + Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) ) + Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' ) + Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) ) + Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) ) + Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a ) + feat.properties['__current_backgroun'] = 'initial_value' + } +} \ No newline at end of file diff --git a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts index fd041335c..172b984ae 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -10,10 +10,7 @@ import { SetDefault, } from "./Conversion" import { LayerConfigJson } from "../Json/LayerConfigJson" -import { - MinimalTagRenderingConfigJson, - TagRenderingConfigJson, -} from "../Json/TagRenderingConfigJson" +import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" import { Utils } from "../../../Utils" import RewritableConfigJson from "../Json/RewritableConfigJson" import SpecialVisualizations from "../../../UI/SpecialVisualizations" @@ -26,7 +23,7 @@ import predifined_filters from "../../../../assets/layers/filters/filters.json" import { TagConfigJson } from "../Json/TagConfigJson" import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson" import ValidationUtils from "./ValidationUtils" -import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization" +import { RenderingSpecification } from "../../../UI/SpecialVisualization" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" import { ConfigMeta } from "../../../UI/Studio/configMeta" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" @@ -1220,6 +1217,54 @@ export class AddRatingBadge extends DesugaringStep { return json } } +export class AutoTitleIcon extends DesugaringStep { + constructor() { + super( + "The auto-icon creates a (non-clickable) title icon based on a tagRendering which has icons", + ["titleIcons"], + "AutoTitleIcon" + ) + } + + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { + json = { ...json } + json.titleIcons = [...json.titleIcons] + for (let i = 0; i < json.titleIcons.length; i++) { + const titleIcon = json.titleIcons[i] + if (typeof titleIcon !== "string") { + continue + } + if (!titleIcon.startsWith("auto:")) { + continue + } + const trId = titleIcon.substring("auto:".length) + const tr = json.tagRenderings.find((tr) => tr["id"] === trId) + if (tr === undefined) { + context + .enters("titleIcons", i) + .err("TagRendering with id " + trId + " not found") + continue + } + const mappings: { if: TagConfigJson, then: string }[] = tr.mappings?.filter(m => m.icon !== undefined) + .map(m => { + const path: string = typeof m.icon === "string" ? m.icon : m.icon.path + const img = `` + return ({ if: m.if, then: img }) + }) + if (mappings.length === 0) { + context + .enters("titleIcons", i) + .warn("TagRendering with id " + trId + " does not have any icons, not generating an icon for this") + continue + } + json.titleIcons[i] = { + id: "title_icon_auto_" + trId, + mappings, + } + } + return json + } +} export class PrepareLayer extends Fuse { constructor(state: DesugaringContext) { @@ -1247,6 +1292,7 @@ export class PrepareLayer extends Fuse { ), new SetDefault("titleIcons", ["icons.defaults"]), new AddRatingBadge(), + new AutoTitleIcon(), new On( "titleIcons", (layer) => diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts index 0cd857bde..50e5870bc 100644 --- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -240,6 +240,8 @@ export interface LayerConfigJson { * Use an empty array to hide them. * Note that "defaults" will insert all the default titleIcons (which are added automatically) * + * Use `auto:` to automatically create an icon based on a tagRendering which has icons + * * Type: icon[] * group: infobox */ From e7c2bd54f7a591b56733a8b7e9ae4bb24c805f80 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 29 Nov 2023 22:59:25 +0100 Subject: [PATCH 12/99] UI: fix #1725 --- assets/layers/icons/icons.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index cb5da7543..8c3435428 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -27,7 +27,7 @@ { "#": "ignore-image-in-then", "if": "wikipedia=", - "then": "WD" + "then": "WD" } ] }, From 595503cfc35c8db3cb4ee4b28f82b7c91ee75dff Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 30 Nov 2023 00:30:46 +0100 Subject: [PATCH 13/99] Fix: improve optimization; add tests --- src/Logic/Tags/And.ts | 32 ++++++++++++++++++++++++++------ src/Logic/Tags/Or.ts | 15 +++++++++++++-- src/Logic/Tags/TagUtils.ts | 8 ++++++++ 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/Logic/Tags/And.ts b/src/Logic/Tags/And.ts index 98da75ae0..dff0919f8 100644 --- a/src/Logic/Tags/And.ts +++ b/src/Logic/Tags/And.ts @@ -233,6 +233,15 @@ export class And extends TagsFilter { return And.construct(newAnds) } + /** + * const raw = {"and": [{"or":["leisure=playground","playground!=forest"]},{"or":["leisure=playground","playground!=forest"]}]} + * const parsed = TagUtils.Tag(raw) + * parsed.optimize().asJson() // => {"or":["leisure=playground","playground!=forest"]} + * + * const raw = {"and": [{"and":["advertising=screen"]}, {"and":["advertising~*"]}]}] + * const parsed = TagUtils.Tag(raw) + * parsed.optimize().asJson() // => "advertising=screen" + */ optimize(): TagsFilter | boolean { if (this.and.length === 0) { return true @@ -294,9 +303,17 @@ export class And extends TagsFilter { optimized.splice(i, 1) i-- } - } else if (v !== opt.value) { - // detected an internal conflict - return false + } else { + if (!v.match(opt.value)) { + // We _know_ that for the key of the RegexTag `opt`, the value will be `v`. + // As such, if `opt.value` cannot match `v`, we detected an internal conflict and can fail + + return false + } else { + // Another tag already provided a _stricter_ value then this regex, so we can remove this one! + optimized.splice(i, 1) + i-- + } } } } @@ -374,10 +391,13 @@ export class And extends TagsFilter { const elements = containedOr.or.filter( (candidate) => !commonValues.some((cv) => cv.shadows(candidate)) ) - newOrs.push(Or.construct(elements)) + if (elements.length > 0) { + newOrs.push(Or.construct(elements)) + } + } + if (newOrs.length > 0) { + commonValues.push(And.construct(newOrs)) } - - commonValues.push(And.construct(newOrs)) const result = new Or(commonValues).optimize() if (result === false) { return false diff --git a/src/Logic/Tags/Or.ts b/src/Logic/Tags/Or.ts index da932049a..a0c0f6622 100644 --- a/src/Logic/Tags/Or.ts +++ b/src/Logic/Tags/Or.ts @@ -162,6 +162,12 @@ export class Or extends TagsFilter { return Or.construct(newOrs) } + /** + * const raw = {"or": [{"and":["leisure=playground","playground!=forest"]},{"and":["leisure=playground","playground!=forest"]}]} + * const parsed = TagUtils.Tag(raw) + * parsed.optimize().asJson() // => {"and":["leisure=playground","playground!=forest"]} + * + */ optimize(): TagsFilter | boolean { if (this.or.length === 0) { return false @@ -241,16 +247,21 @@ export class Or extends TagsFilter { const elements = containedAnd.and.filter( (candidate) => !commonValues.some((cv) => cv.shadows(candidate)) ) + if (elements.length == 0) { + continue + } newAnds.push(And.construct(elements)) } + if (newAnds.length > 0) { + commonValues.push(Or.construct(newAnds)) + } - commonValues.push(Or.construct(newAnds)) const result = new And(commonValues).optimize() if (result === true) { return true } else if (result === false) { // neutral element: skip - } else { + } else if (commonValues.length > 0) { newOrs.push(And.construct(commonValues)) } } diff --git a/src/Logic/Tags/TagUtils.ts b/src/Logic/Tags/TagUtils.ts index 91d3a4ca6..0a8de68d6 100644 --- a/src/Logic/Tags/TagUtils.ts +++ b/src/Logic/Tags/TagUtils.ts @@ -325,6 +325,14 @@ export class TagUtils { return tags } + static optimzeJson(json: TagConfigJson): TagConfigJson | boolean { + const optimized = TagUtils.Tag(json).optimize() + if (optimized === true || optimized === false) { + return optimized + } + return optimized.asJson() + } + /** * Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set. * From 8f7b731d29ca7daec1063a6833716e86333b0ffd Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 30 Nov 2023 00:31:26 +0100 Subject: [PATCH 14/99] Fix: actually include _all_ features --- src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts b/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts index cec3f4de9..703103bc0 100644 --- a/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/NearbyFeatureSource.ts @@ -29,16 +29,16 @@ export default class NearbyFeatureSource implements FeatureSource { this.features = Stores.ListStabilized(this._result) - sources.forEach((source, layer) => {}) + sources.forEach((source, layer) => { + this.registerSource(source, layer) + }) } public registerSource(source: FeatureSource, layerId: string) { - let minzoom = 999 const flayer = this._layerState?.filteredLayers.get(layerId) if (!flayer) { return } - minzoom = Math.min(minzoom, flayer.layerDef.minzoom) const calcSource = this.createSource( source.features, flayer.layerDef.minzoom, From eb444ab84965ae75de0df12e638cbc67ef325e9c Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 30 Nov 2023 00:38:37 +0100 Subject: [PATCH 15/99] Accessibility: small improvements to make keyboard navigation easier. See #1181 --- src/UI/Popup/TagRendering/Questionbox.svelte | 1 - .../TagRendering/TagRenderingEditable.svelte | 4 ++-- .../TagRendering/TagRenderingQuestion.svelte | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/UI/Popup/TagRendering/Questionbox.svelte b/src/UI/Popup/TagRendering/Questionbox.svelte index ff789eb76..6a1bcf8e7 100644 --- a/src/UI/Popup/TagRendering/Questionbox.svelte +++ b/src/UI/Popup/TagRendering/Questionbox.svelte @@ -8,7 +8,6 @@ import type { Feature } from "geojson"; import type { SpecialVisualizationState } from "../../SpecialVisualization"; import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"; - import If from "../../Base/If.svelte"; import TagRenderingQuestion from "./TagRenderingQuestion.svelte"; import Tr from "../../Base/Tr.svelte"; import Translations from "../../i18n/Translations.js"; diff --git a/src/UI/Popup/TagRendering/TagRenderingEditable.svelte b/src/UI/Popup/TagRendering/TagRenderingEditable.svelte index 27d6f09c4..a8c583e68 100644 --- a/src/UI/Popup/TagRendering/TagRenderingEditable.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingEditable.svelte @@ -11,7 +11,7 @@ import Translations from "../../i18n/Translations.js" import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import { Utils } from "../../../Utils" - + import { twMerge } from "tailwind-merge" export let config: TagRenderingConfig export let tags: UIEventSource> export let selectedElement: Feature | undefined @@ -71,7 +71,7 @@ } -
+
{#if config.question && (!editingEnabled || $editingEnabled)} {#if editMode} diff --git a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte index 94f28218f..ab918974e 100644 --- a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte @@ -88,6 +88,9 @@ // TODO this has _to much_ values freeformInput.setData(unseenFreeformValues.join(";")) checkedMappings.push(unseenFreeformValues.length > 0) + freeformInput.addCallbackAndRun(freeformValue => { + checkedMappings[checkedMappings.length - 1] = !!freeformValue + }) } } if (confg.freeform?.key) { @@ -168,6 +171,12 @@ .then((changes) => state.changes.applyChanges(changes)) .catch(console.error) } + + function onInputKeypress(e: Event){ + if (e.key === "Enter") { + onSave(); + } + } let featureSwitchIsTesting = state?.featureSwitchIsTesting ?? new ImmutableStore(false) let featureSwitchIsDebugging = @@ -254,9 +263,8 @@ bind:group={selectedMapping} name={"mappings-radio-" + config.id} value={i} - on:keypress={(e) => { - if (e.key === "Enter") onSave() - }} + on:keypress={onInputKeypress} + /> {/each} @@ -267,6 +275,7 @@ bind:group={selectedMapping} name={"mappings-radio-" + config.id} value={config.mappings?.length} + on:keypress={onInputKeypress} /> {/each} @@ -307,6 +317,7 @@ type="checkbox" name={"mappings-checkbox-" + config.id + "-" + config.mappings?.length} bind:checked={checkedMappings[config.mappings.length]} + on:keypress={onInputKeypress} /> (checkedMappings[config.mappings.length] = true)} on:submit={onSave} /> From 473931891c4aa58d28afcb220f7050a8dbb5c91b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 30 Nov 2023 00:39:55 +0100 Subject: [PATCH 16/99] Favourites: include _all_ tagRenderings --- .gitignore | 1 + assets/layers/favourite/favourite.proto.json | 31 +-- package.json | 2 +- scripts/generateFavouritesLayer.ts | 232 +++++++++++++++++- scripts/generateLayerOverview.ts | 26 +- src/Customizations/AllKnownLayouts.ts | 55 +++-- src/Logic/Actors/GeoLocationHandler.ts | 1 - .../Sources/FavouritesFeatureSource.ts | 7 + .../ThemeConfig/Conversion/Conversion.ts | 23 +- .../Conversion/CreateNoteImportLayer.ts | 2 +- .../ThemeConfig/Conversion/PrepareLayer.ts | 12 +- .../ThemeConfig/Conversion/Validation.ts | 34 ++- src/Models/ThemeViewState.ts | 43 +--- src/UI/BigComponents/UploadTraceToOsmUI.ts | 6 +- src/UI/Favourites/FavouriteSummary.svelte | 10 + src/UI/Favourites/Favourites.svelte | 15 +- src/UI/Popup/ExportAsGpxViz.ts | 18 +- src/UI/SpecialVisualizations.ts | 33 +-- src/UI/ThemeViewGUI.svelte | 23 +- .../Conversion/PrepareTheme.spec.ts | 16 +- 20 files changed, 436 insertions(+), 154 deletions(-) diff --git a/.gitignore b/.gitignore index c5a6e0be2..7124fdc77 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ scratch assets/editor-layer-index.json assets/generated/* src/assets/generated/ +assets/layers/favourite/favourite.json public/*.webmanifest /*.html !/index.html diff --git a/assets/layers/favourite/favourite.proto.json b/assets/layers/favourite/favourite.proto.json index 73ab80572..57ff79f1f 100644 --- a/assets/layers/favourite/favourite.proto.json +++ b/assets/layers/favourite/favourite.proto.json @@ -1,4 +1,5 @@ { + "#":"no-translations", "pointRendering": [ { "location": [ @@ -37,35 +38,9 @@ "render": { "en": "Favourite location", "nl": "Favoriete locatie" - }, - "mappings": [ - { - "if": "name~*", - "then": { - "*": "{name}" - } - } - ] + } }, "tagRenderings": [ - { - "id": "Explanation", - "classes": "thanks", - "icon": { - "class": "large", - "path": "heart" - }, - "render": { - "en": "You marked this location as a personal favourite. As such, it is shown on every map you load.", - "nl": "Je hebt deze locatie als persoonlijke favoriet aangeduid en worden op alle MapComplete-kaarten getoond." - } - }, - { - "id": "show_images", - "render": { - "*": "{image_carousel()}" - } - }, - "all_tags" + ] } diff --git a/package.json b/package.json index f1ecefd07..816714f4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.35.0", + "version": "0.36.0", "repository": "https://github.com/pietervdvn/MapComplete", "description": "A small website to edit OSM easily", "bugs": "https://github.com/pietervdvn/MapComplete/issues", diff --git a/scripts/generateFavouritesLayer.ts b/scripts/generateFavouritesLayer.ts index 334742b45..2cc0abf9d 100644 --- a/scripts/generateFavouritesLayer.ts +++ b/scripts/generateFavouritesLayer.ts @@ -2,24 +2,242 @@ import Script from "./Script" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" import { readFileSync, writeFileSync } from "fs" import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" +import { AllKnownLayoutsLazy } from "../src/Customizations/AllKnownLayouts" +import { Utils } from "../src/Utils" +import { AddEditingElements } from "../src/Models/ThemeConfig/Conversion/PrepareLayer" +import { + MappingConfigJson, + QuestionableTagRenderingConfigJson, +} from "../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" +import { TagConfigJson } from "../src/Models/ThemeConfig/Json/TagConfigJson" +import { TagUtils } from "../src/Logic/Tags/TagUtils" +import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" +import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable" + +export class GenerateFavouritesLayer extends Script { + private readonly layers: LayerConfigJson[] = [] -class PrepareFavouritesLayerJson extends Script { constructor() { super("Prepares the 'favourites'-layer") + const allThemes = new AllKnownLayoutsLazy(false).values() + for (const theme of allThemes) { + if (theme.hideFromOverview) { + continue + } + for (const layer of theme.layers) { + if (!layer.source) { + continue + } + if (layer.source.geojsonSource) { + continue + } + const layerConfig = AllSharedLayers.getSharedLayersConfigs().get(layer.id) + if (!layerConfig) { + continue + } + this.layers.push(layerConfig) + } + } + } + + private addTagRenderings(proto: LayerConfigJson) { + const blacklistedIds = new Set([ + "images", + "questions", + "mapillary", + "leftover-questions", + "last_edit", + "minimap", + "move-button", + "delete-button", + "all-tags", + ...AddEditingElements.addedElements, + ]) + + const generateTagRenderings: (string | QuestionableTagRenderingConfigJson)[] = [] + const trPerId = new Map< + string, + { conditions: TagConfigJson[]; tr: QuestionableTagRenderingConfigJson } + >() + for (const layerConfig of this.layers) { + if (!layerConfig.tagRenderings) { + continue + } + for (const tagRendering of layerConfig.tagRenderings) { + if (typeof tagRendering === "string") { + if (blacklistedIds.has(tagRendering)) { + continue + } + generateTagRenderings.push(tagRendering) + blacklistedIds.add(tagRendering) + continue + } + if (tagRendering["builtin"]) { + continue + } + const id = tagRendering.id + if (blacklistedIds.has(id)) { + continue + } + if (trPerId.has(id)) { + const old = trPerId.get(id).tr + + // We need to figure out if this was a 'recycled' tag rendering or just happens to have the same id + function isSame(fieldName: string) { + return old[fieldName]?.["en"] === tagRendering[fieldName]?.["en"] + } + + const sameQuestion = isSame("question") && isSame("render") + if (!sameQuestion) { + const newTr = Utils.Clone(tagRendering) + newTr.id = layerConfig.id + "_" + newTr.id + if (blacklistedIds.has(newTr.id)) { + continue + } + newTr.condition = { + and: Utils.NoNull([(newTr.condition, layerConfig.source["osmTags"])]), + } + generateTagRenderings.push(newTr) + blacklistedIds.add(newTr.id) + continue + } + } + if (!trPerId.has(id)) { + const newTr = Utils.Clone(tagRendering) + generateTagRenderings.push(newTr) + trPerId.set(newTr.id, { tr: newTr, conditions: [] }) + } + const conditions = trPerId.get(id).conditions + if (tagRendering["condition"]) { + conditions.push({ + and: [tagRendering["condition"], layerConfig.source["osmTags"]], + }) + } else { + conditions.push(layerConfig.source["osmTags"]) + } + } + } + + for (const { tr, conditions } of Array.from(trPerId.values())) { + const optimized = TagUtils.optimzeJson({ or: conditions }) + if (optimized === true) { + continue + } + if (optimized === false) { + throw "Optimized into 'false', this is weird..." + } + tr.condition = optimized + } + + const allTags: QuestionableTagRenderingConfigJson = { + id: "all-tags", + render: { "*": "{all_tags()}" }, + + metacondition: { + or: [ + "__featureSwitchIsDebugging=true", + "mapcomplete-show_tags=full", + "mapcomplete-show_debug=yes", + ], + }, + } + proto.tagRenderings = [ + ...generateTagRenderings, + ...proto.tagRenderings, + "questions", + allTags, + ] + } + + private addTitle(proto: LayerConfigJson) { + const mappings: MappingConfigJson[] = [] + for (const layer of this.layers) { + const t = layer.title + const tags: TagConfigJson = layer.source["osmTags"] + if (!t) { + continue + } + if (typeof t === "string") { + mappings.push({ if: tags, then: t }) + } else if (t["render"] !== undefined || t["mappings"] !== undefined) { + const tr = t + for (let i = 0; i < (tr.mappings ?? []).length; i++) { + const mapping = tr.mappings[i] + const optimized = TagUtils.optimzeJson({ + and: [mapping.if, tags], + }) + if (optimized === false) { + console.warn( + "The following tags yielded 'false':", + JSON.stringify(mapping.if), + JSON.stringify(tags) + ) + continue + } + if (optimized === true) { + console.error( + "The following tags yielded 'false':", + JSON.stringify(mapping.if), + JSON.stringify(tags) + ) + throw "Tags for title optimized to true" + } + + if (!mapping.then) { + throw ( + "The title has a missing 'then' for mapping " + + i + + " in layer " + + layer.id + ) + } + mappings.push({ + if: optimized, + then: mapping.then, + }) + } + if (tr.render) { + mappings.push({ + if: tags, + then: tr.render, + }) + } + } else { + mappings.push({ if: tags, then: >t }) + } + } + + if (proto.title["mappings"]) { + mappings.unshift(...proto.title["mappings"]) + } + if (proto.title["render"]) { + mappings.push({ + if: "id~*", + then: proto.title["render"], + }) + } + + proto.title = { + mappings, + } } async main(args: string[]): Promise { - const allConfigs = AllSharedLayers.getSharedLayersConfigs() + console.log("Generating the favourite layer: stealing _all_ tagRenderings") const proto = this.readLayer("favourite/favourite.proto.json") - const questions = allConfigs.get("questions") - proto.tagRenderings.push(...questions.tagRenderings) - + this.addTagRenderings(proto) + this.addTitle(proto) writeFileSync("./assets/layers/favourite/favourite.json", JSON.stringify(proto, null, " ")) } private readLayer(path: string): LayerConfigJson { - return JSON.parse(readFileSync("./assets/layers/" + path, "utf8")) + try { + return JSON.parse(readFileSync("./assets/layers/" + path, "utf8")) + } catch (e) { + console.error("Could not read ./assets/layers/" + path) + throw e + } } } -new PrepareFavouritesLayerJson().run() +new GenerateFavouritesLayer().run() diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 32f06ee64..dcfbb71ad 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -28,6 +28,7 @@ import { QuestionableTagRenderingConfigJson } from "../src/Models/ThemeConfig/Js import LayerConfig from "../src/Models/ThemeConfig/LayerConfig" import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig" import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext" +import { GenerateFavouritesLayer } from "./generateFavouritesLayer" // This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files. // It spits out an overview of those to be used to load them @@ -381,16 +382,11 @@ class LayerOverviewUtils extends Script { forceReload ) - writeFileSync( - "./src/assets/generated/known_themes.json", - JSON.stringify({ - themes: Array.from(sharedThemes.values()), - }) - ) - writeFileSync( "./src/assets/generated/known_layers.json", - JSON.stringify({ layers: Array.from(sharedLayers.values()) }) + JSON.stringify({ + layers: Array.from(sharedLayers.values()).filter((l) => l.id !== "favourite"), + }) ) const mcChangesPath = "./assets/themes/mapcomplete-changes/mapcomplete-changes.json" @@ -428,6 +424,19 @@ class LayerOverviewUtils extends Script { ConversionContext.construct([], []) ) + for (const [_, theme] of sharedThemes) { + theme.layers = theme.layers.filter( + (l) => Constants.added_by_default.indexOf(l["id"]) < 0 + ) + } + + writeFileSync( + "./src/assets/generated/known_themes.json", + JSON.stringify({ + themes: Array.from(sharedThemes.values()), + }) + ) + const end = new Date() const millisNeeded = end.getTime() - start.getTime() if (AllSharedLayers.getSharedLayersConfigs().size == 0) { @@ -791,4 +800,5 @@ class LayerOverviewUtils extends Script { } } +new GenerateFavouritesLayer().run() new LayerOverviewUtils().run() diff --git a/src/Customizations/AllKnownLayouts.ts b/src/Customizations/AllKnownLayouts.ts index 12c27223c..cbd28cf5b 100644 --- a/src/Customizations/AllKnownLayouts.ts +++ b/src/Customizations/AllKnownLayouts.ts @@ -1,45 +1,54 @@ import known_themes from "../assets/generated/known_themes.json" import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" +import favourite from "../assets/generated/layers/favourite.json" import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson" +import { AllSharedLayers } from "./AllSharedLayers" +import Constants from "../Models/Constants" /** * Somewhat of a dictionary, which lazily parses needed themes */ export class AllKnownLayoutsLazy { - private readonly dict: Map LayoutConfig }> = - new Map() - constructor() { + private readonly raw: Map = new Map() + private readonly dict: Map = new Map() + + constructor(includeFavouriteLayer = true) { for (const layoutConfigJson of known_themes["themes"]) { - this.dict.set(layoutConfigJson.id, { - func: () => { - const layout = new LayoutConfig(layoutConfigJson, true) - for (let i = 0; i < layout.layers.length; i++) { - let layer = layout.layers[i] - if (typeof layer === "string") { - throw "Layer " + layer + " was not expanded in " + layout.id - } + for (const layerId of Constants.added_by_default) { + if (layerId === "favourite") { + if (includeFavouriteLayer) { + layoutConfigJson.layers.push(favourite) } - return layout - }, - }) + continue + } + const defaultLayer = AllSharedLayers.getSharedLayersConfigs().get(layerId) + if (defaultLayer === undefined) { + console.error("Could not find builtin layer", layerId) + continue + } + layoutConfigJson.layers.push(defaultLayer) + } + this.raw.set(layoutConfigJson.id, layoutConfigJson) } } + public getConfig(key: string): LayoutConfigJson { + return this.raw.get(key) + } + public get(key: string): LayoutConfig { - const thunk = this.dict.get(key) - if (thunk === undefined) { - return undefined + const cached = this.dict.get(key) + if (cached !== undefined) { + return cached } - if (thunk["data"]) { - return thunk["data"] - } - const layout = thunk["func"]() - this.dict.set(key, { data: layout }) + + const layout = new LayoutConfig(this.getConfig(key)) + this.dict.set(key, layout) return layout } public keys() { - return this.dict.keys() + return this.raw.keys() } public values() { diff --git a/src/Logic/Actors/GeoLocationHandler.ts b/src/Logic/Actors/GeoLocationHandler.ts index 9333a8413..691be8dbb 100644 --- a/src/Logic/Actors/GeoLocationHandler.ts +++ b/src/Logic/Actors/GeoLocationHandler.ts @@ -173,7 +173,6 @@ export default class GeoLocationHandler { properties[k] = location[k] } } - console.debug("Current location object:", location) properties["_all"] = JSON.stringify(location) const feature = { diff --git a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts index bd6d52b4d..01703987f 100644 --- a/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/FavouritesFeatureSource.ts @@ -16,6 +16,11 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { private readonly _osmConnection: OsmConnection private readonly _detectedIds: Store + /** + * All favourites, including the ones which are filtered away because they are already displayed + */ + public readonly allFavourites: Store + constructor( connection: OsmConnection, indexedSource: FeaturePropertiesStore, @@ -53,6 +58,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { ) super(featuresWithoutAlreadyPresent) + this.allFavourites = features this._osmConnection = connection this._detectedIds = Stores.ListStabilized( @@ -76,6 +82,7 @@ export default class FavouritesFeatureSource extends StaticFeatureSource { const geometry = <[number, number]>JSON.parse(prefs[key]) const properties = FavouritesFeatureSource.getPropertiesFor(prefs, id) properties._orig_layer = prefs[FavouritesFeatureSource.prefix + id + "-layer"] + properties._orig_theme = prefs[FavouritesFeatureSource.prefix + id + "-theme"] properties.id = osmId properties._favourite = "yes" diff --git a/src/Models/ThemeConfig/Conversion/Conversion.ts b/src/Models/ThemeConfig/Conversion/Conversion.ts index b6422bd55..d74028731 100644 --- a/src/Models/ThemeConfig/Conversion/Conversion.ts +++ b/src/Models/ThemeConfig/Conversion/Conversion.ts @@ -2,6 +2,7 @@ import { LayerConfigJson } from "../Json/LayerConfigJson" import { Utils } from "../../../Utils" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" import { ConversionContext } from "./ConversionContext" +import { T } from "vitest/dist/types-aac763a5" export interface DesugaringContext { tagRenderings: Map @@ -81,18 +82,36 @@ export class Pure extends Conversion { } } +export class Bypass extends DesugaringStep { + private readonly _applyIf: (t: T) => boolean + private readonly _step: DesugaringStep + constructor(applyIf: (t: T) => boolean, step: DesugaringStep) { + super("Applies the step on the object, if the object satisfies the predicate", [], "Bypass") + this._applyIf = applyIf + this._step = step + } + + convert(json: T, context: ConversionContext): T { + if (!this._applyIf(json)) { + return json + } + return this._step.convert(json, context) + } +} + export class Each extends Conversion { private readonly _step: Conversion private readonly _msg: string + private readonly _filter: (x: X) => boolean - constructor(step: Conversion, msg?: string) { + constructor(step: Conversion, options?: { msg?: string }) { super( "Applies the given step on every element of the list", [], "OnEach(" + step.name + ")" ) this._step = step - this._msg = msg + this._msg = options?.msg } convert(values: X[], context: ConversionContext): Y[] { diff --git a/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts b/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts index c88eb6541..aa587e65e 100644 --- a/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts +++ b/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts @@ -85,7 +85,7 @@ export default class CreateNoteImportLayer extends Conversion { } export class AddEditingElements extends DesugaringStep { + static addedElements: string[] = [ + "minimap", + "just_created", + "split_button", + "move_button", + "delete_button", + "last_edit", + "favourite_state", + "all_tags", + ] private readonly _desugaring: DesugaringContext constructor(desugaring: DesugaringContext) { @@ -1210,7 +1220,7 @@ class AddFavouriteBadges extends DesugaringStep { } convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { - if (json.id === "favourite") { + if (json.source === "special" || json.source === "special:library") { return json } const pr = json.pointRendering?.[0] diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts index 62a495bf7..8db411c2f 100644 --- a/src/Models/ThemeConfig/Conversion/Validation.ts +++ b/src/Models/ThemeConfig/Conversion/Validation.ts @@ -1,4 +1,4 @@ -import { Conversion, DesugaringStep, Each, Fuse, On, Pipe, Pure } from "./Conversion" +import { Bypass, Conversion, DesugaringStep, Each, Fuse, On } from "./Conversion" import { LayerConfigJson } from "../Json/LayerConfigJson" import LayerConfig from "../LayerConfig" import { Utils } from "../../../Utils" @@ -11,7 +11,6 @@ import { TagUtils } from "../../../Logic/Tags/TagUtils" import { ExtractImages } from "./FixImages" import { And } from "../../../Logic/Tags/And" import Translations from "../../../UI/i18n/Translations" -import Svg from "../../../Svg" import FilterConfigJson from "../Json/FilterConfigJson" import DeleteConfig from "../DeleteConfig" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" @@ -276,9 +275,9 @@ export class ValidateThemeAndLayers extends Fuse { new On( "layers", new Each( - new Pipe( - new ValidateLayer(undefined, isBuiltin, doesImageExist, false, true), - new Pure((x) => x?.raw) + new Bypass( + (layer) => Constants.added_by_default.indexOf(layer.id) < 0, + new ValidateLayerConfig(undefined, isBuiltin, doesImageExist, false, true) ) ) ) @@ -968,7 +967,7 @@ export class ValidateTagRenderings extends Fuse { "Various validation on tagRenderingConfigs", new DetectShadowedMappings(layerConfig), new DetectConflictingAddExtraTags(), - // new DetectNonErasedKeysInMappings(), + // TODO enable new DetectNonErasedKeysInMappings(), new DetectMappingsWithImages(doesImageExist), new On("render", new ValidatePossibleLinks()), new On("question", new ValidatePossibleLinks()), @@ -1350,6 +1349,29 @@ export class PrevalidateLayer extends DesugaringStep { } } +export class ValidateLayerConfig extends DesugaringStep { + private readonly validator: ValidateLayer + constructor( + path: string, + isBuiltin: boolean, + doesImageExist: DoesImageExist, + studioValidations: boolean = false, + skipDefaultLayers: boolean = false + ) { + super("Thin wrapper around 'ValidateLayer", [], "ValidateLayerConfig") + this.validator = new ValidateLayer( + path, + isBuiltin, + doesImageExist, + studioValidations, + skipDefaultLayers + ) + } + + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { + return this.validator.convert(json, context).raw + } +} export class ValidateLayer extends Conversion< LayerConfigJson, { parsed: LayerConfig; raw: LayerConfigJson } diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index a94ad07b4..fbf17de77 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -462,6 +462,7 @@ export default class ThemeViewState implements SpecialVisualizationState { * @private */ private selectClosestAtCenter(i: number = 0) { + this.mapProperties.lastKeyNavigation.setData(Date.now() / 1000) const toSelect = this.closestFeatures.features.data[i] if (!toSelect) { return @@ -567,46 +568,6 @@ export default class ThemeViewState implements SpecialVisualizationState { }) } - private addLastClick(last_click: LastClickFeatureSource) { - // The last_click gets a _very_ special treatment as it interacts with various parts - - this.featureProperties.trackFeatureSource(last_click) - this.indexedFeatures.addSource(last_click) - - last_click.features.addCallbackAndRunD((features) => { - if (this.selectedLayer.data?.id === "last_click") { - // The last-click location moved, but we have selected the last click of the previous location - // So, we update _after_ clearing the selection to make sure no stray data is sticking around - this.selectedElement.setData(undefined) - this.selectedElement.setData(features[0]) - } - }) - - new ShowDataLayer(this.map, { - features: new FilteringFeatureSource(this.newPointDialog, last_click), - doShowLayer: this.featureSwitches.featureSwitchEnableLogin, - layer: this.newPointDialog.layerDef, - selectedElement: this.selectedElement, - selectedLayer: this.selectedLayer, - metaTags: this.userRelatedState.preferencesAsTags, - onClick: (feature: Feature) => { - if (this.mapProperties.zoom.data < Constants.minZoomLevelToAddNewPoint) { - this.map.data.flyTo({ - zoom: Constants.minZoomLevelToAddNewPoint, - center: this.mapProperties.lastClickLocation.data, - }) - return - } - // We first clear the selection to make sure no weird state is around - this.selectedLayer.setData(undefined) - this.selectedElement.setData(undefined) - - this.selectedElement.setData(feature) - this.selectedLayer.setData(this.newPointDialog.layerDef) - }, - }) - } - /** * Add the special layers to the map */ @@ -663,9 +624,7 @@ export default class ThemeViewState implements SpecialVisualizationState { } const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range") - const rangeIsDisplayed = rangeFLayer?.isDisplayed - if ( !QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef)) ) { diff --git a/src/UI/BigComponents/UploadTraceToOsmUI.ts b/src/UI/BigComponents/UploadTraceToOsmUI.ts index 5344da228..2b281ee06 100644 --- a/src/UI/BigComponents/UploadTraceToOsmUI.ts +++ b/src/UI/BigComponents/UploadTraceToOsmUI.ts @@ -121,9 +121,9 @@ export default class UploadTraceToOsmUI extends LoginToggle { ]).SetClass("flex p-2 rounded-xl border-2 subtle-border items-center"), new Toggle( confirmPanel, - new SubtleButton(new SvelteUIElement(Upload), t.title).onClick(() => - clicked.setData(true) - ), + new SubtleButton(new SvelteUIElement(Upload), t.title) + .onClick(() => clicked.setData(true)) + .SetClass("w-full"), clicked ), uploadFinished diff --git a/src/UI/Favourites/FavouriteSummary.svelte b/src/UI/Favourites/FavouriteSummary.svelte index e69de29bb..92f34be74 100644 --- a/src/UI/Favourites/FavouriteSummary.svelte +++ b/src/UI/Favourites/FavouriteSummary.svelte @@ -0,0 +1,10 @@ + + +
+ {JSON.stringify(properties)} + {properties?.id ?? "undefined"} + OSM +
diff --git a/src/UI/Favourites/Favourites.svelte b/src/UI/Favourites/Favourites.svelte index ff6e0331f..cb0382e46 100644 --- a/src/UI/Favourites/Favourites.svelte +++ b/src/UI/Favourites/Favourites.svelte @@ -1,8 +1,19 @@ + +
+ You marked {$favourites.length} locations as a favourite location. + + This list is only visible to you +{#each $favourites as f} + +{/each} +
diff --git a/src/UI/Popup/ExportAsGpxViz.ts b/src/UI/Popup/ExportAsGpxViz.ts index c7821da10..a5acf8582 100644 --- a/src/UI/Popup/ExportAsGpxViz.ts +++ b/src/UI/Popup/ExportAsGpxViz.ts @@ -31,14 +31,16 @@ export class ExportAsGpxViz implements SpecialVisualization { t.downloadFeatureAsGpx.SetClass("font-bold text-lg"), t.downloadGpxHelper.SetClass("subtle"), ]).SetClass("flex flex-col") - ).onClick(() => { - console.log("Exporting as GPX!") - const tags = tagSource.data - const title = layer.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "gpx_track" - const gpx = GeoOperations.toGpx(>feature, title) - Utils.offerContentsAsDownloadableFile(gpx, title + "_mapcomplete_export.gpx", { - mimetype: "{gpx=application/gpx+xml}", + ) + .SetClass("w-full") + .onClick(() => { + console.log("Exporting as GPX!") + const tags = tagSource.data + const title = layer.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "gpx_track" + const gpx = GeoOperations.toGpx(>feature, title) + Utils.offerContentsAsDownloadableFile(gpx, title + "_mapcomplete_export.gpx", { + mimetype: "{gpx=application/gpx+xml}", + }) }) - }) } } diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index d2da94d4b..139a9e60e 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -534,6 +534,9 @@ export default class SpecialVisualizations { feature: Feature, layer: LayerConfig ): BaseUIElement { + if (!layer.deletion) { + return undefined + } return new SvelteUIElement(DeleteWizard, { tags: tagSource, deleteConfig: layer.deletion, @@ -873,20 +876,22 @@ export default class SpecialVisualizations { t.downloadFeatureAsGeojson.SetClass("font-bold text-lg"), t.downloadGeoJsonHelper.SetClass("subtle"), ]).SetClass("flex flex-col") - ).onClick(() => { - console.log("Exporting as Geojson") - const tags = tagSource.data - const title = - layer?.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "geojson" - const data = JSON.stringify(feature, null, " ") - Utils.offerContentsAsDownloadableFile( - data, - title + "_mapcomplete_export.geojson", - { - mimetype: "application/vnd.geo+json", - } - ) - }) + ) + .onClick(() => { + console.log("Exporting as Geojson") + const tags = tagSource.data + const title = + layer?.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "geojson" + const data = JSON.stringify(feature, null, " ") + Utils.offerContentsAsDownloadableFile( + data, + title + "_mapcomplete_export.geojson", + { + mimetype: "application/vnd.geo+json", + } + ) + }) + .SetClass("w-full") }, }, { diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index 0db04b1f8..221dfeef3 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -15,7 +15,7 @@ import type { MapProperties } from "../Models/MapProperties"; import Geosearch from "./BigComponents/Geosearch.svelte"; import Translations from "./i18n/Translations"; - import { CogIcon, EyeIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"; + import { CogIcon, EyeIcon, HeartIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"; import Tr from "./Base/Tr.svelte"; import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"; import FloatOver from "./Base/FloatOver.svelte"; @@ -64,6 +64,8 @@ import Community from "../assets/svg/Community.svelte"; import Download from "../assets/svg/Download.svelte"; import Share from "../assets/svg/Share.svelte"; + import FavouriteSummary from "./Favourites/FavouriteSummary.svelte"; + import Favourites from "./Favourites/Favourites.svelte"; export let state: ThemeViewState; let layout = state.layout; @@ -493,22 +495,31 @@
+ + Your favourites +
+ +
+

Your favourite locations

+ +
+
-
+
-
+
-
+
new PrivacyPolicy()} />
- -
+ +
diff --git a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts index 009c9f08a..ec4118934 100644 --- a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts +++ b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts @@ -179,7 +179,21 @@ describe("PrepareTheme", () => { id: "layer-example", name: null, minzoom: 18, - pointRendering: [{ location: ["point"], label: "xyz" }], + pointRendering: [ + { + location: ["point"], + label: "xyz", + iconBadges: [ + { + if: "_favourite=yes", + then: { + id: "circlewhiteheartred", + render: "circle:white;heart:red", + }, + }, + ], + }, + ], lineRendering: [{ width: 1 }], titleIcons: [], }) From 8e733693080fe642d9efb747a5c06c3b6c6c9a04 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 30 Nov 2023 01:41:41 +0100 Subject: [PATCH 17/99] UX: do not show nearby features box if there are none --- src/UI/ThemeViewGUI.svelte | 152 ++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index 0197ba58e..f617e85ec 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -66,71 +66,70 @@ import OpenJosm from "./Base/OpenJosm.svelte" export let state: ThemeViewState - let layout = state.layout + let layout = state.layout - let maplibremap: UIEventSource = state.map - let selectedElement: UIEventSource = state.selectedElement - let selectedLayer: UIEventSource = state.selectedLayer + let maplibremap: UIEventSource = state.map + let selectedElement: UIEventSource = state.selectedElement + let selectedLayer: UIEventSource = state.selectedLayer - let currentZoom = state.mapProperties.zoom - let showCrosshair = state.userRelatedState.showCrosshair - let arrowKeysWereUsed = state.mapProperties.lastKeyNavigation - let centerFeatures = state.closestFeatures.features - $: console.log("Centerfeatures are", $centerFeatures) - const selectedElementView = selectedElement.map( - (selectedElement) => { - // Svelte doesn't properly reload some of the legacy UI-elements - // As such, we _reconstruct_ the selectedElementView every time a new feature is selected - // This is a bit wasteful, but until everything is a svelte-component, this should do the trick - const layer = selectedLayer.data - if (selectedElement === undefined || layer === undefined) { - return undefined - } + let currentZoom = state.mapProperties.zoom + let showCrosshair = state.userRelatedState.showCrosshair + let arrowKeysWereUsed = state.mapProperties.lastKeyNavigation + let centerFeatures = state.closestFeatures.features + const selectedElementView = selectedElement.map( + (selectedElement) => { + // Svelte doesn't properly reload some of the legacy UI-elements + // As such, we _reconstruct_ the selectedElementView every time a new feature is selected + // This is a bit wasteful, but until everything is a svelte-component, this should do the trick + const layer = selectedLayer.data + if (selectedElement === undefined || layer === undefined) { + return undefined + } - if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) { - return undefined - } + if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) { + return undefined + } - const tags = state.featureProperties.getStore(selectedElement.properties.id) - return new SvelteUIElement(SelectedElementView, { - state, - layer, - selectedElement, - tags, - }).SetClass("h-full w-full") - }, - [selectedLayer] - ) + const tags = state.featureProperties.getStore(selectedElement.properties.id) + return new SvelteUIElement(SelectedElementView, { + state, + layer, + selectedElement, + tags, + }).SetClass("h-full w-full") + }, + [selectedLayer], + ) - const selectedElementTitle = selectedElement.map( - (selectedElement) => { - // Svelte doesn't properly reload some of the legacy UI-elements - // As such, we _reconstruct_ the selectedElementView every time a new feature is selected - // This is a bit wasteful, but until everything is a svelte-component, this should do the trick - const layer = selectedLayer.data - if (selectedElement === undefined || layer === undefined) { - return undefined - } + const selectedElementTitle = selectedElement.map( + (selectedElement) => { + // Svelte doesn't properly reload some of the legacy UI-elements + // As such, we _reconstruct_ the selectedElementView every time a new feature is selected + // This is a bit wasteful, but until everything is a svelte-component, this should do the trick + const layer = selectedLayer.data + if (selectedElement === undefined || layer === undefined) { + return undefined + } - const tags = state.featureProperties.getStore(selectedElement.properties.id) - return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags }) - }, - [selectedLayer] - ) + const tags = state.featureProperties.getStore(selectedElement.properties.id) + return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags }) + }, + [selectedLayer], + ) - let mapproperties: MapProperties = state.mapProperties - let featureSwitches: FeatureSwitchState = state.featureSwitches - let availableLayers = state.availableLayers - let userdetails = state.osmConnection.userDetails - let currentViewLayer = layout.layers.find((l) => l.id === "current_view") - let rasterLayer: Store = state.mapProperties.rasterLayer - let rasterLayerName = - rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name - onDestroy( - rasterLayer.addCallbackAndRunD((l) => { - rasterLayerName = l.properties.name - }) - ) + let mapproperties: MapProperties = state.mapProperties + let featureSwitches: FeatureSwitchState = state.featureSwitches + let availableLayers = state.availableLayers + let userdetails = state.osmConnection.userDetails + let currentViewLayer = layout.layers.find((l) => l.id === "current_view") + let rasterLayer: Store = state.mapProperties.rasterLayer + let rasterLayerName = + rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name + onDestroy( + rasterLayer.addCallbackAndRunD((l) => { + rasterLayerName = l.properties.name + }), + )
@@ -214,7 +213,7 @@ state.guistate.openFilterView()}> - + @@ -231,16 +230,17 @@
- {#if $arrowKeysWereUsed !== undefined} -
- {#each $centerFeatures as feat, i (feat.properties.id)} -
- {i + 1}. - -
- {/each} -
+ {#if $centerFeatures.length > 0} +
+ {#each $centerFeatures as feat, i (feat.properties.id)} +
+ {i + 1}. + +
+ {/each} +
+ {/if} {/if}
@@ -257,7 +257,7 @@ mapproperties.zoom.update((z) => z - 1)}> - + @@ -350,7 +350,7 @@
- +
@@ -374,7 +374,7 @@
- +
@@ -389,7 +389,7 @@ new CopyrightPanel(state)} slot="content3" />
- +
@@ -441,12 +441,12 @@ - + - + @@ -495,7 +495,7 @@
- +
@@ -513,7 +513,7 @@
- + From 46fe1c5795a110c541ed97548c426b205705ff2d Mon Sep 17 00:00:00 2001 From: eMerzh Date: Thu, 30 Nov 2023 20:56:18 +0100 Subject: [PATCH 18/99] fix: correct default sed param for BSD sed flavor --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbd6b213f..6fca534fa 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "generate:schemas": "ts2json-schema -p src/Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && echo 'tsjson is done' && vite-node scripts/fixSchemas.ts ", "fix:schemas": "vite-node scripts/fixSchemas.ts ", "watch:schemas": "cd Models/ThemeConfig/Json & ls | entr -s 'npm run generate:schemas' ", - "generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js", + "generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i.bak \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js && rm public/service-worker.js.bak", "optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", "generate:stats": "vite-node scripts/GenerateSeries.ts", "reset:layeroverview": "mkdir -p ./src/assets/generated/layers; echo {\\\"themes\\\":[]} > ./src/assets/generated/known_themes.json && echo {\\\"layers\\\": []} > ./src/assets/generated/known_layers.json && rm -f ./src/assets/generated/layers/*.json && rm -f ./src/assets/generated/themes/*.json && cp ./assets/layers/usersettings/usersettings.json ./src/assets/generated/layers/usersettings.json && npm run generate:layeroverview && vite-node scripts/generateLayerOverview.ts -- --force", From 834e4b5e0234754268fcb6c85d1d84500ca98a67 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Thu, 30 Nov 2023 23:46:08 +0100 Subject: [PATCH 19/99] Update plug types from Wikipedia --- .../charging_station/charging_station.json | 123 +++++++++++++++++- assets/layers/charging_station/types.csv | 4 +- 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index 91d305c3f..1828087e2 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -330,14 +330,79 @@ }, "hideInAnswer": { "or": [ - "_country!=be", + "_country!=af", + "_country!=al", + "_country!=dz", + "_country!=as", + "_country!=ad", + "_country!=ao", + "_country!=am", + "_country!=aw", + "_country!=az", + "_country!=by", + "_country!=bt", + "_country!=ba", + "_country!=bg", + "_country!=cv", + "_country!=td", + "_country!=cl", + "_country!=hr", + "_country!=dk", + "_country!=eg", + "_country!=ee", + "_country!=et", + "_country!=fo", "_country!=fr", - "_country!=ma", - "_country!=tn", - "_country!=pl", - "_country!=cs", + "_country!=pf", + "_country!=ge", + "_country!=gr", + "_country!=gl", + "_country!=gn", + "_country!=gw", + "_country!=is", + "_country!=id", + "_country!=ir", + "_country!=jo", + "_country!=kz", + "_country!=kg", + "_country!=la", + "_country!=lv", + "_country!=lr", + "_country!=ly", + "_country!=lt", + "_country!=lu", + "_country!=mo", + "_country!=mr", + "_country!=md", + "_country!=mc", + "_country!=mn", + "_country!=me", + "_country!=mz", + "_country!=nl", + "_country!=nc", + "_country!=ne", + "_country!=kp", + "_country!=mk", + "_country!=pt", + "_country!=qa", + "_country!=ro", + "_country!=ru", + "_country!=rw", + "_country!=sm", "_country!=sk", - "_country!=mo" + "_country!=si", + "_country!=kr", + "_country!=es", + "_country!=sr", + "_country!=tj", + "_country!=th", + "_country!=tl", + "_country!=tr", + "_country!=tm", + "_country!=ua", + "_country!=uy", + "_country!=uz", + "_country!=vn" ] } }, @@ -378,6 +443,52 @@ "icon": { "path": "./assets/layers/charging_station/TypeE.svg", "class": "medium" + }, + "hideInAnswer": { + "or": [ + "_country!=be", + "_country!=bj", + "_country!=bf", + "_country!=bi", + "_country!=cm", + "_country!=cf", + "_country!=td", + "_country!=km", + "_country!=cz", + "_country!=dk", + "_country!=dj", + "_country!=gq", + "_country!=et", + "_country!=fo", + "_country!=fr", + "_country!=gf", + "_country!=pf", + "_country!=gl", + "_country!=gp", + "_country!=gw", + "_country!=la", + "_country!=lr", + "_country!=mg", + "_country!=ml", + "_country!=mq", + "_country!=mr", + "_country!=mu", + "_country!=mc", + "_country!=mn", + "_country!=ma", + "_country!=ne", + "_country!=pl", + "_country!=pt", + "_country!=rw", + "_country!=mf", + "_country!=pm", + "_country!=sn", + "_country!=sk", + "_country!=sy", + "_country!=tl", + "_country!=tn", + "_country!=uz" + ] } }, { diff --git a/assets/layers/charging_station/types.csv b/assets/layers/charging_station/types.csv index d31c004ba..8d9795616 100644 --- a/assets/layers/charging_station/types.csv +++ b/assets/layers/charging_station/types.csv @@ -1,6 +1,6 @@ key,image,description:en,countryWhiteList,countryBlackList,commonVoltages,commonCurrents,commonOutputs,description:nl,associatedVehicleTypes,neverAssociatedWith,extraVisualisationCondition -socket:schuko,CEE7_4F.svg,Schuko wall plug without ground pin (CEE7/4 type F),be;fr;ma;tn;pl;cs;sk;mo,,230,16,3.6 kW,Schuko stekker zonder aardingspin (CEE7/4 type F),*,, -socket:typee,TypeE.svg,European wall plug with ground pin (CEE7/4 type E),,,230,16,3 kW;22 kW;,Europese stekker met aardingspin (CEE7/4 type E),*,, +socket:schuko,CEE7_4F.svg,Schuko wall plug without ground pin (CEE7/4 type F),af;al;dz;as;ad;ao;am;aw;az;by;bt;ba;bg;cv;td;cl;hr;dk;eg;ee;et;fo;fr;pf;ge;gr;gl;gn;gw;is;id;ir;jo;kz;kg;la;lv;lr;ly;lt;lu;mo;mr;md;mc;mn;me;mz;nl;nc;ne;kp;mk;pt;qa;ro;ru;rw;sm;sk;si;kr;es;sr;tj;th;tl;tr;tm;ua;uy;uz;vn,,230,16,3.6 kW,Schuko stekker zonder aardingspin (CEE7/4 type F),*,, +socket:typee,TypeE.svg,European wall plug with ground pin (CEE7/4 type E),be;bj;bf;bi;cm;cf;td;km;cz;dk;dj;gq;et;fo;fr;gf;pf;gl;gp;gw;la;lr;mg;ml;mq;mr;mu;mc;mn;ma;ne;pl;pt;rw;mf;pm;sn;sk;sy;tl;tn;uz,,230,16,3 kW;22 kW;,Europese stekker met aardingspin (CEE7/4 type E),*,, socket:chademo,Chademo_type4.svg,Chademo,,,500,120,50 kW,Chademo,car;motorcar;hgv;bus,bicycle;scooter, socket:type1_cable,Type1_J1772.svg,Type 1 with cable (J1772),,,200;240,32,3.7 kW;7 kW,Type 1 met kabel (J1772),car;motorcar;hgv;bus,bicycle;scooter, socket:type1,Type1_J1772.svg,Type 1 without cable (J1772),,,200;240,32,3.7 kW;6.6 kW;7 kW;7.2 kW,Type 1 zonder kabel (J1772),car;motorcar;hgv;bus,bicycle;scooter, From 76874e6de89949d00816acf78ab224678c92aaab Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Fri, 1 Dec 2023 00:05:57 +0100 Subject: [PATCH 20/99] Update presets --- .vscode/settings.json | 5 +- .../charging_station/charging_station.json | 15 +++-- .../charging_station.protojson | 55 ++++++++++--------- assets/layers/charging_station/csvToJson.ts | 2 +- langs/layers/de.json | 2 +- langs/layers/en.json | 2 +- langs/layers/nl.json | 2 +- 7 files changed, 43 insertions(+), 40 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e1ede94e..e975a613f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,5 +18,8 @@ "[svelte]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.formatOnSave": true + "editor.formatOnSave": true, + "files.associations": { + "*.protojson": "json" + } } diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index 1828087e2..691616f83 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -329,7 +329,7 @@ "class": "medium" }, "hideInAnswer": { - "or": [ + "and": [ "_country!=af", "_country!=al", "_country!=dz", @@ -445,7 +445,7 @@ "class": "medium" }, "hideInAnswer": { - "or": [ + "and": [ "_country!=be", "_country!=bj", "_country!=bf", @@ -1142,7 +1142,7 @@ ] }, { - "or": [ + "and": [ "_country!=us" ] } @@ -5213,16 +5213,15 @@ "tags": [ "amenity=charging_station", "motorcar=no", - "bicycle=yes", - "socket:typee=1" + "bicycle=yes" ], "title": { - "en": "a charging station for electrical bikes with a normal european wall plug (meant to charge electrical bikes)", - "nl": "een oplaadpunt voor elektrische fietsen met een gewoon Europees stopcontact (speciaal bedoeld voor fietsen)", + "en": "a charging station for electrical bikes", + "nl": "een oplaadpunt voor elektrische fietsen", "ca": "una estació de càrrega per a bicicletes elèctriques amb un endoll de paret europeu normal (destinat a carregar bicicletes elèctriques)", "cs": "nabíjecí stanice pro elektrokola s běžnou evropskou zástrčkou (určeno k nabíjení elektrických kol)", "da": "en ladestation til elektriske cykler med et normalt europæisk vægstik (beregnet til opladning af elektriske cykler)", - "de": "eine Ladestation für Elektrofahrräder mit einer normalen europäischen Steckdose (zum Laden von Elektrofahrrädern)", + "de": "eine Ladestation für Elektrofahrräder", "es": "una estación de carga para bicicletas eléctricas con un enchufe de pared europeo normal (pensado para cargar bicicletas eléctricas)" } }, diff --git a/assets/layers/charging_station/charging_station.protojson b/assets/layers/charging_station/charging_station.protojson index 828045f39..7f8356a66 100644 --- a/assets/layers/charging_station/charging_station.protojson +++ b/assets/layers/charging_station/charging_station.protojson @@ -735,30 +735,32 @@ "point", "centroid" ], - "marker": [{ - "icon": "pin", - "color": "#fff" - },{ - "icon": { - "render":"./assets/themes/charging_stations/plug.svg", - "mappings": [ - { - "if": "bicycle=yes", - "then": "./assets/themes/charging_stations/bicycle.svg" - }, - { - "if": { - "or": [ - "car=yes", - "motorcar=yes" - ] + "marker": [ + { + "icon": "pin", + "color": "#fff" + }, + { + "icon": { + "render": "./assets/themes/charging_stations/plug.svg", + "mappings": [ + { + "if": "bicycle=yes", + "then": "./assets/themes/charging_stations/bicycle.svg" }, - "then": "./assets/themes/charging_stations/car.svg" - } - ] - + { + "if": { + "or": [ + "car=yes", + "motorcar=yes" + ] + }, + "then": "./assets/themes/charging_stations/car.svg" + } + ] + } } - }], + ], "iconBadges": [ { "if": { @@ -802,12 +804,11 @@ "tags": [ "amenity=charging_station", "motorcar=no", - "bicycle=yes", - "socket:typee=1" + "bicycle=yes" ], "title": { - "en": "charging station for electrical bikes with a normal european wall plug ", - "nl": "oplaadpunt voor elektrische fietsen met een gewone, europese stekker " + "en": "charging station for electrical bikes", + "nl": "oplaadpunt voor elektrische fietsen" } }, { @@ -949,4 +950,4 @@ }, "neededChangesets": 10 } -} +} \ No newline at end of file diff --git a/assets/layers/charging_station/csvToJson.ts b/assets/layers/charging_station/csvToJson.ts index ff1a50fb6..e0ee8f610 100644 --- a/assets/layers/charging_station/csvToJson.ts +++ b/assets/layers/charging_station/csvToJson.ts @@ -91,7 +91,7 @@ function run(file, protojson) { if (e.countryWhiteList.length > 0) { // This is a 'hideInAnswer', thus _reverse_ logic! const countries = e.countryWhiteList.map(country => "_country!=" + country) //HideInAnswer if it is in the wrong country - json["hideInAnswer"] = {or: countries} + json["hideInAnswer"] = {and: countries} // Should be and, as we want to hide if it does not match any of the countries } else if (e.countryBlackList.length > 0) { const countries = e.countryBlackList.map(country => "_country=" + country) //HideInAnswer if it is in the wrong country json["hideInAnswer"] = {or: countries} diff --git a/langs/layers/de.json b/langs/layers/de.json index 4067c6339..e6d3e3058 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -1993,7 +1993,7 @@ "name": "Ladestationen", "presets": { "0": { - "title": "eine Ladestation für Elektrofahrräder mit einer normalen europäischen Steckdose (zum Laden von Elektrofahrrädern)" + "title": "eine Ladestation für Elektrofahrräder" }, "1": { "title": "Eine Ladestation für Elektrofahrzeuge" diff --git a/langs/layers/en.json b/langs/layers/en.json index 4fdcba826..b5a7cd153 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -1993,7 +1993,7 @@ "name": "Charging stations", "presets": { "0": { - "title": "a charging station for electrical bikes with a normal european wall plug (meant to charge electrical bikes)" + "title": "a charging station for electrical bikes" }, "1": { "title": "a charging station for cars" diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 5184c7223..5db8c5b88 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -1842,7 +1842,7 @@ "name": "Oplaadpunten", "presets": { "0": { - "title": "een oplaadpunt voor elektrische fietsen met een gewoon Europees stopcontact (speciaal bedoeld voor fietsen)" + "title": "een oplaadpunt voor elektrische fietsen" }, "1": { "title": "een oplaadstation voor elektrische auto's" From 4eb8b086e2fe5bab3e1cc40a96b73169f53cc369 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 14:52:50 +0100 Subject: [PATCH 21/99] UX: fix #1729: ignore accents in theme search --- src/UI/BigComponents/MoreScreen.ts | 4 +- src/Utils.ts | 174 +++++++++++++++-------------- 2 files changed, 93 insertions(+), 85 deletions(-) diff --git a/src/UI/BigComponents/MoreScreen.ts b/src/UI/BigComponents/MoreScreen.ts index 045bf3ec5..e280d577c 100644 --- a/src/UI/BigComponents/MoreScreen.ts +++ b/src/UI/BigComponents/MoreScreen.ts @@ -118,7 +118,7 @@ export default class MoreScreen extends Combine { if (search === undefined) { return true } - search = search.toLocaleLowerCase() + search = Utils.RemoveDiacritics(search.toLocaleLowerCase()) if (search.length > 3 && layout.id.toLowerCase().indexOf(search) >= 0) { return true } @@ -131,7 +131,7 @@ export default class MoreScreen extends Combine { continue } const term = entity["*"] ?? entity[Locale.language.data] - if (term?.toLowerCase()?.indexOf(search) >= 0) { + if (Utils.RemoveDiacritics(term?.toLowerCase())?.indexOf(search) >= 0) { return true } } diff --git a/src/Utils.ts b/src/Utils.ts index c89e4a468..fc834a06d 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -11,7 +11,7 @@ export class Utils { public static readonly assets_path = "./assets/svg/" public static externalDownloadFunction: ( url: string, - headers?: any + headers?: any, ) => Promise<{ content: string } | { redirect: string }> public static Special_visualizations_tagsToApplyHelpText = `These can either be a tag to add, such as \`amenity=fast_food\` or can use a substitution, e.g. \`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. @@ -150,7 +150,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be if (Utils.runningFromConsole) { return } - DOMPurify.addHook("afterSanitizeAttributes", function (node) { + DOMPurify.addHook("afterSanitizeAttributes", function(node) { // set all elements owning target to target=_blank + add noopener noreferrer const target = node.getAttribute("target") if (target) { @@ -172,7 +172,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be */ public static ParseVisArgs( specs: { name: string; defaultValue?: string }[], - args: string[] + args: string[], ): Record { const parsed: Record = {} if (args.length > specs.length) { @@ -320,7 +320,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be object: any, name: string, init: () => any, - whenDone?: () => void + whenDone?: () => void, ) { Object.defineProperty(object, name, { enumerable: false, @@ -343,7 +343,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be object: any, name: string, init: () => Promise, - whenDone?: () => void + whenDone?: () => void, ) { Object.defineProperty(object, name, { enumerable: false, @@ -483,7 +483,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static SubstituteKeys( txt: string | undefined, tags: Record | undefined, - useLang?: string + useLang?: string, ): string | undefined { if (txt === undefined) { return undefined @@ -519,7 +519,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be "SubstituteKeys received a BaseUIElement to substitute in - this is probably a bug and will be downcast to a string\nThe key is", key, "\nThe value is", - v + v, ) v = v.InnerConstructElement()?.textContent } @@ -561,38 +561,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be target.push(...source) } - /** - * Recursively rewrites all keys from `+key`, `key+` and `=key` into `key - * - * Utils.CleanMergeObject({"condition":{"and+":["xyz"]}} // => {"condition":{"and":["xyz"]}} - * @param obj - * @constructor - * @private - */ - private static CleanMergeObject(obj: any) { - if (Array.isArray(obj)) { - const result = [] - for (const el of obj) { - result.push(Utils.CleanMergeObject(el)) - } - return result - } - if (typeof obj !== "object") { - return obj - } - const newObj = {} - for (let objKey in obj) { - let cleanKey = objKey - if (objKey.startsWith("+") || objKey.startsWith("=")) { - cleanKey = objKey.substring(1) - } else if (objKey.endsWith("+") || objKey.endsWith("=")) { - cleanKey = objKey.substring(0, objKey.length - 1) - } - newObj[cleanKey] = Utils.CleanMergeObject(obj[objKey]) - } - return newObj - } - /** * Copies all key-value pairs of the source into the target. This will change the target * If the key starts with a '+', the values of the list will be appended to the target instead of overwritten @@ -664,7 +632,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be if (!Array.isArray(targetV)) { throw new Error( "Cannot concatenate: value to add is not an array: " + - JSON.stringify(targetV) + JSON.stringify(targetV), ) } if (Array.isArray(sourceV)) { @@ -672,9 +640,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } else { throw new Error( "Could not merge concatenate " + - JSON.stringify(sourceV) + - " and " + - JSON.stringify(targetV) + JSON.stringify(sourceV) + + " and " + + JSON.stringify(targetV), ) } } else { @@ -719,7 +687,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be path: string[], object: any, replaceLeaf: (leaf: any, travelledPath: string[]) => any, - travelledPath: string[] = [] + travelledPath: string[] = [], ): void { if (object == null) { return @@ -750,7 +718,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } if (Array.isArray(sub)) { sub.forEach((el, i) => - Utils.WalkPath(path.slice(1), el, replaceLeaf, [...travelledPath, head, "" + i]) + Utils.WalkPath(path.slice(1), el, replaceLeaf, [...travelledPath, head, "" + i]), ) return } @@ -767,7 +735,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be path: string[], object: any, collectedList: { leaf: any; path: string[] }[] = [], - travelledPath: string[] = [] + travelledPath: string[] = [], ): { leaf: any; path: string[] }[] { if (object === undefined || object === null) { return collectedList @@ -797,7 +765,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be if (Array.isArray(sub)) { sub.forEach((el, i) => - Utils.CollectPath(path.slice(1), el, collectedList, [...travelledPath, "" + i]) + Utils.CollectPath(path.slice(1), el, collectedList, [...travelledPath, "" + i]), ) return collectedList } @@ -841,7 +809,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be json: any, f: (v: object | number | string | boolean | undefined, path: string[]) => any, isLeaf: (object) => boolean = undefined, - path: string[] = [] + path: string[] = [], ) { if (json === undefined || json === null) { return f(json, path) @@ -880,7 +848,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be json: any, collect: (v: number | string | boolean | undefined, path: string[]) => any, isLeaf: (object) => boolean = undefined, - path = [] + path = [], ): void { if (json === undefined) { return @@ -955,7 +923,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be continue } const i = part.charCodeAt(0) - result += '"' + keys[i] + '":' + part.substring(1) + result += "\"" + keys[i] + "\":" + part.substring(1) } return result @@ -982,7 +950,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be url: string, headers?: any, method: "POST" | "GET" | "PUT" | "UPDATE" | "DELETE" | "OPTIONS" = "GET", - content?: string + content?: string, ): Promise< | { content: string } | { redirect: string } @@ -1047,7 +1015,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static async downloadJsonCached( url: string, maxCacheTimeMs: number, - headers?: any + headers?: any, ): Promise { const result = await Utils.downloadJsonAdvanced(url, headers) if (result["content"]) { @@ -1059,7 +1027,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static async downloadJsonCachedAdvanced( url: string, maxCacheTimeMs: number, - headers?: any + headers?: any, ): Promise<{ content: any } | { error: string; url: string; statuscode?: number }> { const cached = Utils._download_cache.get(url) if (cached !== undefined) { @@ -1069,9 +1037,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } const promise = /*NO AWAIT as we work with the promise directly */ Utils.downloadJsonAdvanced( - url, - headers - ) + url, + headers, + ) Utils._download_cache.set(url, { promise, timestamp: new Date().getTime() }) return await promise } @@ -1086,7 +1054,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static async downloadJsonAdvanced( url: string, - headers?: any + headers?: any, ): Promise<{ content: any } | { error: string; url: string; statuscode?: number }> { const injected = Utils.injectedDownloads[url] if (injected !== undefined) { @@ -1095,7 +1063,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } const result = await Utils.downloadAdvanced( url, - Utils.Merge({ accept: "application/json" }, headers ?? {}) + Utils.Merge({ accept: "application/json" }, headers ?? {}), ) if (result["error"] !== undefined) { return <{ error: string; url: string; statuscode?: number }>result @@ -1115,7 +1083,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be "due to", e, "\n", - e.stack + e.stack, ) return { error: "malformed", url } } @@ -1136,7 +1104,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be | "{gpx=application/gpx+xml}" | "application/json" | "image/png" - } + }, ) { const element = document.createElement("a") let file @@ -1240,7 +1208,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be e.preventDefault() return false }, - false + false, ) } @@ -1324,7 +1292,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static sortedByLevenshteinDistance( reference: string, ts: T[], - getName: (t: T) => string + getName: (t: T) => string, ): T[] { const withDistance: [T, number][] = ts.map((t) => [ t, @@ -1350,7 +1318,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be track[j][i] = Math.min( track[j][i - 1] + 1, // deletion track[j - 1][i] + 1, // insertion - track[j - 1][i - 1] + indicator // substitution + track[j - 1][i - 1] + indicator, // substitution ) } } @@ -1359,7 +1327,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be public static MapToObj( d: Map, - onValue: (t: V, key: string) => T + onValue: (t: V, key: string) => T, ): Record { const o = {} const keys = Array.from(d.keys()) @@ -1376,7 +1344,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be * Utils.TransposeMap({"a" : ["b", "c"], "x" : ["b", "y"]}) // => {"b" : ["a", "x"], "c" : ["a"], "y" : ["x"]} */ public static TransposeMap( - d: Record + d: Record, ): Record { const newD: Record = {} @@ -1450,7 +1418,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } public static asDict( - tags: { key: string; value: string | number }[] + tags: { key: string; value: string | number }[], ): Map { const d = new Map() @@ -1491,21 +1459,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be element.scrollIntoView({ behavior: "smooth", block: "nearest" }) } - private static findParentWithScrolling(element: HTMLBaseElement): HTMLBaseElement { - // Check if the element itself has scrolling - if (element.scrollHeight > element.clientHeight) { - return element - } - - // If the element does not have scrolling, check if it has a parent element - if (!element.parentElement) { - return null - } - - // If the element has a parent, repeat the process for the parent element - return Utils.findParentWithScrolling(element.parentElement) - } - /** * Returns true if the contents of `a` are the same (and in the same order) as `b`. * Might have false negatives in some cases @@ -1572,7 +1525,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be * */ public static splitIntoSubstitutionParts( - template: string + template: string, ): ({ message: string } | { subs: string })[] { const preparts = template.split("{") const spec: ({ message: string } | { subs: string })[] = [] @@ -1633,6 +1586,13 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } } + public static RemoveDiacritics(str?: string): string { + if(!str){ + return str + } + return str.normalize("NFD").replace(/\p{Diacritic}/gu, "") + } + public static randomString(length: number): string { let result = "" for (let i = 0; i < length; i++) { @@ -1641,9 +1601,57 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } return result } + + /** + * Recursively rewrites all keys from `+key`, `key+` and `=key` into `key + * + * Utils.CleanMergeObject({"condition":{"and+":["xyz"]}} // => {"condition":{"and":["xyz"]}} + * @param obj + * @constructor + * @private + */ + private static CleanMergeObject(obj: any) { + if (Array.isArray(obj)) { + const result = [] + for (const el of obj) { + result.push(Utils.CleanMergeObject(el)) + } + return result + } + if (typeof obj !== "object") { + return obj + } + const newObj = {} + for (let objKey in obj) { + let cleanKey = objKey + if (objKey.startsWith("+") || objKey.startsWith("=")) { + cleanKey = objKey.substring(1) + } else if (objKey.endsWith("+") || objKey.endsWith("=")) { + cleanKey = objKey.substring(0, objKey.length - 1) + } + newObj[cleanKey] = Utils.CleanMergeObject(obj[objKey]) + } + return newObj + } + + private static findParentWithScrolling(element: HTMLBaseElement): HTMLBaseElement { + // Check if the element itself has scrolling + if (element.scrollHeight > element.clientHeight) { + return element + } + + // If the element does not have scrolling, check if it has a parent element + if (!element.parentElement) { + return null + } + + // If the element has a parent, repeat the process for the parent element + return Utils.findParentWithScrolling(element.parentElement) + } + private static colorDiff( c0: { r: number; g: number; b: number }, - c1: { r: number; g: number; b: number } + c1: { r: number; g: number; b: number }, ) { return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) + Math.abs(c0.b - c1.b) } From 48216c1a7f5cd13de856657966bbbe524382cec1 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 15:31:29 +0100 Subject: [PATCH 22/99] UI: fix #1723 --- public/css/index-tailwind-output.css | 12 +- .../TagRendering/TagRenderingQuestion.svelte | 352 +++++++++--------- 2 files changed, 183 insertions(+), 181 deletions(-) diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 3d49a619b..b1b43a769 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -841,6 +841,10 @@ video { margin-right: 3rem; } +.mb-4 { + margin-bottom: 1rem; +} + .mt-4 { margin-top: 1rem; } @@ -877,10 +881,6 @@ video { margin-right: 0.25rem; } -.mb-4 { - margin-bottom: 1rem; -} - .ml-1 { margin-left: 0.25rem; } @@ -1784,6 +1784,10 @@ video { padding-bottom: 0.5rem; } +.pt-1 { + padding-top: 0.25rem; +} + .text-center { text-align: center; } diff --git a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte index 0131a20fa..83c37af8e 100644 --- a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte @@ -1,202 +1,200 @@ {#if question !== undefined}
-
-
+
- -
+
{#if config.questionhint} @@ -213,7 +211,7 @@ {#if config.mappings?.length >= 8}
- +
{/if} From 2a3a78bc69eea38a83378f02717bc9fdc1cd5414 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 16:07:07 +0100 Subject: [PATCH 23/99] Themes: enable reviews for climbing areas and gyms --- assets/layers/climbing_area/climbing_area.json | 1 + assets/layers/climbing_gym/climbing_gym.json | 1 + 2 files changed, 2 insertions(+) diff --git a/assets/layers/climbing_area/climbing_area.json b/assets/layers/climbing_area/climbing_area.json index 4e77dfac7..6e54aaee8 100644 --- a/assets/layers/climbing_area/climbing_area.json +++ b/assets/layers/climbing_area/climbing_area.json @@ -343,6 +343,7 @@ }, "id": "Rock type (crag/rock/cliff only)" }, + "reviews", { "id": "default_climbing_questions", "builtin": [ diff --git a/assets/layers/climbing_gym/climbing_gym.json b/assets/layers/climbing_gym/climbing_gym.json index 476845d0d..87857221a 100644 --- a/assets/layers/climbing_gym/climbing_gym.json +++ b/assets/layers/climbing_gym/climbing_gym.json @@ -129,6 +129,7 @@ }, "payment-options", "opening_hours", + "reviews", { "id": "shoe_rental", "question": { From def640fb1c97c581e4688c8c0a50f4e295d9458b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 16:07:23 +0100 Subject: [PATCH 24/99] Themes: add 'artwork' questions to drinking water fountains --- .../layers/drinking_water/drinking_water.json | 152 ++++++++++++------ 1 file changed, 107 insertions(+), 45 deletions(-) diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index ff9bdb5b9..f877bfa04 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -62,7 +62,11 @@ "cs": "Pitná voda" } }, - "titleIcons": ["icons.defaults", "auto:type", "auto:seasonal"], + "titleIcons": [ + "icons.defaults", + "auto:type", + "auto:seasonal" + ], "pointRendering": [ { "iconBadges": [ @@ -75,6 +79,10 @@ ] }, "then": "close:#c33" + }, + { + "if": "tourism=artwork", + "then": "circle:white;./assets/layers/artwork/artwork.svg" } ], "iconSize": "40,40", @@ -150,7 +158,10 @@ "mappings": [ { "if": "operational_status=", - "addExtraTags": ["disused:amenity=","amenity=drinking_water"], + "addExtraTags": [ + "disused:amenity=", + "amenity=drinking_water" + ], "then": { "en": "This drinking water works", "nl": "Deze drinkwaterfontein werkt", @@ -297,7 +308,7 @@ { "if": "fee=yes", "then": { - "en":"One needs to pay to use this drinking water point" + "en": "One needs to pay to use this drinking water point" } } ] @@ -310,71 +321,123 @@ "mappings": [ { "if": "seasonal=no", - "then":{ - "en":"This drinking water point is available all around the year" + "then": { + "en": "This drinking water point is available all around the year" } }, { "if": "seasonal=summer", - "then":{ - "en":"This drinking water point is only available in summer" + "then": { + "en": "This drinking water point is only available in summer" } }, { "if": "seasonal=spring;summer;autumn", "icon": "./assets/layers/drinking_water/no_winter.svg", - "then":{ - "en":"This drinking water point is closed during the winter" + "then": { + "en": "This drinking water point is closed during the winter" } } ] }, - {"builtin":["opening_hours_24_7"], + { + "builtin": [ + "opening_hours_24_7" + ], "override": { - "questionHint":{ - "en":"These are the opening hours if the drinking water fountain is operational." + "questionHint": { + "en": "These are the opening hours if the drinking water fountain is operational." }, - "+mappings":[ + "+mappings": [ { - "if":{ + "if": { "and": [ "seasonal!=no", - {"or":[ - { - "and":[ - "seasonal!~.*winter.*", - "_now:date~....-(12|01|02)-.." - ] - }, - { - "and":[ - "seasonal!~.*spring.*", - "_now:date~....-(03|04|05)-.." - ] - }, - { - "and":[ - "seasonal!~.*summer.*", - "_now:date~....-(06|07|08)-.." - ] - }, - { - "and":[ - "seasonal!~.*autumn.*", - "_now:date~....-(09|10|11)-.." - ] - } - ]} + { + "or": [ + { + "and": [ + "seasonal!~.*winter.*", + "_now:date~....-(12|01|02)-.." + ] + }, + { + "and": [ + "seasonal!~.*spring.*", + "_now:date~....-(03|04|05)-.." + ] + }, + { + "and": [ + "seasonal!~.*summer.*", + "_now:date~....-(06|07|08)-.." + ] + }, + { + "and": [ + "seasonal!~.*autumn.*", + "_now:date~....-(09|10|11)-.." + ] + } + ] + } ] }, - "then":{ - "en": "This drinking water fountain is closed this season." + "then": { + "en": "This drinking water fountain is closed this season. As such, the opening hours are not shown." }, - "hideInAnswer":true + "hideInAnswer": true } ] } }, + { + "id": "bench-artwork", + "question": { + "en": "Does this drinking water fountain have an artistic element?", + "nl": "Heeft dit drinkwaterpunt een geintegreerd kunstwerk?" + }, + "mappings": [ + { + "if": "tourism=artwork", + "addExtraTags": [ + "not:tourism:artwork=" + ], + "then": { + "en": "This drinking water point has an integrated artwork", + "nl": "Dit drinkwaterpunt heeft een geintegreerd kunstwerk" + } + }, + { + "if": "not:tourism:artwork=yes", + "then": { + "en": "This drinking water point does not have an integrated artwork", + "nl": "Dit drinkwaterpunt heeft geen geïntegreerd kunstwerk" + }, + "addExtraTags": [ + "tourism=" + ] + }, + { + "if": "tourism=", + "then": { + "en": "This drinking water point probably doesn't have an integrated artwork", + "nl": "Dit drinkwaterpunt heeft waarschijnlijk geen geïntegreerd kunstwerk" + }, + "hideInAnswer": true + } + ], + "questionHint": { + "en": "E.g. it has an integrated statue or other non-trivial, creative work", + "nl": "Bijvoorbeeld een standbeeld of ander, niet-triviaal kunstwerk" + } + }, + { + "builtin": "artwork.*artwork-question", + "override": { + "condition": "tourism=artwork" + } + }, { "id": "render-closest-drinking-water", "render": { @@ -390,7 +453,6 @@ }, "condition": "_closest_other_drinking_water_id~*" } - ], "deletion": { "softDeletionTags": { @@ -443,7 +505,7 @@ ] }, "then": { - "en":"This is a historic, manual water pump where no drinking water can be found" + "en": "This is a historic, manual water pump where no drinking water can be found" } } ] From 2b3853e3c7a6019465c0b9301045f34a5811d32e Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 18:12:53 +0100 Subject: [PATCH 25/99] Fix build --- assets/layers/drinking_water/drinking_water.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index f877bfa04..ec4afb95d 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -341,9 +341,7 @@ ] }, { - "builtin": [ - "opening_hours_24_7" - ], + "builtin": "opening_hours_24_7", "override": { "questionHint": { "en": "These are the opening hours if the drinking water fountain is operational." From 99942587079d8d3d0f88c916f05098631e7858fd Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 22:33:08 +0100 Subject: [PATCH 26/99] Add delete option for layers --- scripts/studioServer.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/scripts/studioServer.ts b/scripts/studioServer.ts index b1505e583..05f82cd07 100644 --- a/scripts/studioServer.ts +++ b/scripts/studioServer.ts @@ -44,6 +44,36 @@ async function prepareFile(url: string): Promise { } return null } +async function handleDelete(req: http.IncomingMessage, res: ServerResponse) { + let body = "" + req.on("data", (chunk) => { + body = body + chunk + }) + const paths = req.url.split("/") + console.log("Got a valid delete to:", paths.join("/")) + for (let i = 1; i < paths.length; i++) { + const p = paths.slice(0, i) + const dir = STATIC_PATH + p.join("/") + if (!fs.existsSync(dir)) { + res.writeHead(304, { "Content-Type": MIME_TYPES.html }) + res.write("No parent directory, nothing deleted", "utf8") + res.end() + return + } + } + const path = STATIC_PATH + paths.join("/") + if(!fs.existsSync(path)){ + res.writeHead(304, { "Content-Type": MIME_TYPES.html }) + res.write("File not found", "utf8") + res.end() + return + } + + fs.renameSync(path, path+".bak") + res.writeHead(200, { "Content-Type": MIME_TYPES.html }) + res.write("File moved to backup", "utf8") + res.end() +} async function handlePost(req: http.IncomingMessage, res: ServerResponse) { let body = "" @@ -101,6 +131,11 @@ http.createServer(async (req: http.IncomingMessage, res) => { return } + if(req.method === "DELETE"){ + await handleDelete(req, res) + return + } + const url = new URL(`http://127.0.0.1/` + req.url) console.log("URL pathname is") if (url.pathname.endsWith("overview")) { From 80a3fdc1a6bef2a800145d33f94dcde87df65d84 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 22:34:09 +0100 Subject: [PATCH 27/99] Add timestamping to script --- scripts/studioServer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/studioServer.ts b/scripts/studioServer.ts index 05f82cd07..1648f8b8f 100644 --- a/scripts/studioServer.ts +++ b/scripts/studioServer.ts @@ -83,6 +83,7 @@ async function handlePost(req: http.IncomingMessage, res: ServerResponse) { await new Promise((resolve) => req.on("end", resolve)) + console.log(new Date().toISOString()) let parsed: any try { parsed = JSON.parse(body) From eb12112e1196c9848fdfee492e46b9a2e8db25be Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 22:39:13 +0100 Subject: [PATCH 28/99] Add logging --- scripts/studioServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/studioServer.ts b/scripts/studioServer.ts index 1648f8b8f..264dd5f08 100644 --- a/scripts/studioServer.ts +++ b/scripts/studioServer.ts @@ -115,7 +115,7 @@ async function handlePost(req: http.IncomingMessage, res: ServerResponse) { http.createServer(async (req: http.IncomingMessage, res) => { try { - console.log(req.method + " " + req.url, "from:", req.headers.origin) + console.log(req.method + " " + req.url, "from:", req.headers.origin, new Date().toISOString()) res.setHeader( "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept" From 22095f4640fcb394a9dd826717297f10a152d5e5 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 1 Dec 2023 22:42:02 +0100 Subject: [PATCH 29/99] Debugging --- scripts/studioServer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/studioServer.ts b/scripts/studioServer.ts index 264dd5f08..f7597f505 100644 --- a/scripts/studioServer.ts +++ b/scripts/studioServer.ts @@ -133,6 +133,7 @@ http.createServer(async (req: http.IncomingMessage, res) => { } if(req.method === "DELETE"){ + console.log("Got a DELETE", new Date()) await handleDelete(req, res) return } From eb5cc4d78c97b8690b794f4710323a763a3b19f1 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sat, 2 Dec 2023 00:24:55 +0100 Subject: [PATCH 30/99] Studio: add delete button for layers --- src/UI/Studio/EditLayer.svelte | 13 ++++++++++++- src/UI/Studio/EditLayerState.ts | 3 +++ src/UI/Studio/StudioServer.ts | 9 ++++++++- src/UI/StudioGUI.svelte | 31 ++++++++++++++++--------------- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/UI/Studio/EditLayer.svelte b/src/UI/Studio/EditLayer.svelte index 8faf4bac0..f90358d33 100644 --- a/src/UI/Studio/EditLayer.svelte +++ b/src/UI/Studio/EditLayer.svelte @@ -9,7 +9,7 @@ import { Utils } from "../../Utils" import type { ConversionMessage } from "../../Models/ThemeConfig/Conversion/Conversion" import ErrorIndicatorForRegion from "./ErrorIndicatorForRegion.svelte" - import { ChevronRightIcon } from "@rgossiaux/svelte-heroicons/solid" + import { ChevronRightIcon, TrashIcon } from "@rgossiaux/svelte-heroicons/solid" import SchemaBasedInput from "./SchemaBasedInput.svelte" import FloatOver from "../Base/FloatOver.svelte" import TagRenderingInput from "./TagRenderingInput.svelte" @@ -21,6 +21,7 @@ const layerSchema: ConfigMeta[] = layerSchemaRaw export let state: EditLayerState + export let backToStudio: () => void let messages = state.messages let hasErrors = messages.mapD( (m: ConversionMessage[]) => m.filter((m) => m.level === "error").length @@ -72,6 +73,10 @@ }) let highlightedItem: UIEventSource = state.highlightedItem + function deleteLayer() { + state.delete() + backToStudio() + }
@@ -113,6 +118,12 @@
+
+ + +
diff --git a/src/UI/Studio/EditLayerState.ts b/src/UI/Studio/EditLayerState.ts index bf5bd09e1..2f80830ec 100644 --- a/src/UI/Studio/EditLayerState.ts +++ b/src/UI/Studio/EditLayerState.ts @@ -107,6 +107,9 @@ export abstract class EditJsonState { return entry } + public async delete(){ + await this.server.delete(this.getId().data, this.category) + } public getStoreFor(path: ReadonlyArray): UIEventSource { const key = path.join(".") diff --git a/src/UI/Studio/StudioServer.ts b/src/UI/Studio/StudioServer.ts index 0151376a5..bda3ac12c 100644 --- a/src/UI/Studio/StudioServer.ts +++ b/src/UI/Studio/StudioServer.ts @@ -58,7 +58,14 @@ export default class StudioServer { return undefined } } - + async delete(id: string, category: "layers" | "themes") { + if (id === undefined || id === "") { + return + } + await fetch(this.urlFor(id, category), { + method: "DELETE" + }) + } async update(id: string, config: string, category: "layers" | "themes") { if (id === undefined || id === "") { return diff --git a/src/UI/StudioGUI.svelte b/src/UI/StudioGUI.svelte index fb1b64753..a53512db1 100644 --- a/src/UI/StudioGUI.svelte +++ b/src/UI/StudioGUI.svelte @@ -260,7 +260,7 @@
{:else if state === "editing_layer"} - + {state = undefined}}> {/if} - - -{#if { intro, tagrenderings: intro_tagrenderings }[$showIntro]?.sections} - { + {#if { intro, tagrenderings: intro_tagrenderings }[$showIntro]?.sections} + { showIntro.setData("no") }} - > -
- { + > +
+ { showIntro.setData("no") }} - /> -
- -{/if} + /> +
+
+ {/if} + + + From 04b0d825fbc1878475f6af26e9e11213c7d1956d Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sat, 2 Dec 2023 00:46:43 +0100 Subject: [PATCH 31/99] Chore: formatting --- assets/layers/sport_pitch/sport_pitch.json | 4 ++-- assets/themes/cyclofix/cyclofix.json | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/assets/layers/sport_pitch/sport_pitch.json b/assets/layers/sport_pitch/sport_pitch.json index 9da40da8e..2a7d07649 100644 --- a/assets/layers/sport_pitch/sport_pitch.json +++ b/assets/layers/sport_pitch/sport_pitch.json @@ -459,8 +459,8 @@ { "if": "surface=fine_gravel", "then": { - "en":"The surface is fine gravel", - "nl":"De ondergrond bestaat uit grind" + "en": "The surface is fine gravel", + "nl": "De ondergrond bestaat uit grind" } } ], diff --git a/assets/themes/cyclofix/cyclofix.json b/assets/themes/cyclofix/cyclofix.json index 5f94fda48..a52093c2e 100644 --- a/assets/themes/cyclofix/cyclofix.json +++ b/assets/themes/cyclofix/cyclofix.json @@ -102,9 +102,10 @@ "=pointRendering": [ { "marker": [ - {"icon": "pin", - "color":"#ba2792"} - , + { + "icon": "pin", + "color": "#ba2792" + }, { "icon": "./assets/themes/cyclofix/key.svg" } From cb744f1a6112c4e2afb8975fdc6bb22583789e57 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sat, 2 Dec 2023 00:46:52 +0100 Subject: [PATCH 32/99] Remove duplcate 'reviews' --- assets/themes/climbing/climbing.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/themes/climbing/climbing.json b/assets/themes/climbing/climbing.json index 426c72999..da398b01a 100644 --- a/assets/themes/climbing/climbing.json +++ b/assets/themes/climbing/climbing.json @@ -345,8 +345,7 @@ "key": "access:description" } }, - "questions", - "reviews" + "questions" ] } }, From 72400f03520a102e4daf1061eed3d4631839e283 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sat, 2 Dec 2023 00:48:53 +0100 Subject: [PATCH 33/99] Chore: formatting, translation sync, update of ELI --- .../themes/facadegardens/facadegardens.json | 4 +- assets/themes/sidewalks/sidewalks.json | 40 +++++------ langs/layers/en.json | 70 +++++++++++++++++++ langs/layers/nl.json | 21 ++++++ public/css/index-tailwind-output.css | 4 ++ src/assets/editor-layer-index.json | 38 ++++++---- 6 files changed, 141 insertions(+), 36 deletions(-) diff --git a/assets/themes/facadegardens/facadegardens.json b/assets/themes/facadegardens/facadegardens.json index 03bc83229..c7b2ee42c 100644 --- a/assets/themes/facadegardens/facadegardens.json +++ b/assets/themes/facadegardens/facadegardens.json @@ -542,7 +542,9 @@ "leisure=garden", "garden:type=facade_garden" ], - "snapToLayer":["walls_and_buildings"], + "snapToLayer": [ + "walls_and_buildings" + ], "title": { "nl": "een geveltuintje", "en": "a facade garden", diff --git a/assets/themes/sidewalks/sidewalks.json b/assets/themes/sidewalks/sidewalks.json index 459225a4a..03b439468 100644 --- a/assets/themes/sidewalks/sidewalks.json +++ b/assets/themes/sidewalks/sidewalks.json @@ -166,31 +166,31 @@ { "if": "sidewalk:left|right=yes", "then": { - "en": "There is a sidewalk on this side of the road", - "de": "Es gibt einen Bürgersteig auf dieser Straßenseite", - "da": "Der er et fortov på denne side af vejen", - "nl": "Er is een stoep aan deze kant van de weg", - "fr": "Il y a un trottoir de ce côté de la route", - "ca": "Hi ha una vorera a aquest costat del carrer", - "es": "Hay una acera en este lado de la calle", - "cs": "Na této straně silnice je chodník", - "it": "C'è un marciapiede su questo lato della strada", - "pl": "Jest chodnik z boku drogi" + "en": "Yes, there is a sidewalk on this side of the road", + "de": "Ja, es gibt einen Bürgersteig auf dieser Straßenseite", + "da": "Ja, der er et fortov på denne side af vejen", + "nl": "Ja, er is een stoep aan deze kant van de weg", + "fr": "Oui, il y a un trottoir de ce côté de la route", + "ca": "Sí, hi ha una vorera a aquest costat del carrer", + "es": "Sí, hay una acera en este lado de la calle", + "cs": "Ano, na této straně silnice je chodník", + "it": "Sì, c'è un marciapiede su questo lato della strada", + "pl": "Tak, jest chodnik z boku drogi" } }, { "if": "sidewalk:left|right=no", "then": { - "en": "There is no sidewalk to walk on", - "de": "Es gibt keinen Bürgersteig für Fußgänger", - "da": "Der er ikke noget fortov at gå på", - "nl": "Er is geen stoep om op te lopen", - "fr": "Il n'y a pas de trottoir où marcher", - "ca": "No hi ha vorera per la que caminar", - "es": "No hay acera por la que caminar", - "cs": "Není tu žádný chodník", - "it": "Non c'è un marciapiede su cui camminare", - "pl": "Nie ma chodnika, którym można chodzić" + "en": "No, there is no sidewalk to walk on", + "de": "Nein, es gibt keinen Bürgersteig für Fußgänger", + "da": "Nej, der er ikke noget fortov at gå på", + "nl": "Nee, er is geen stoep om op te lopen", + "fr": "Non, il n'y a pas de trottoir où marcher", + "ca": "No, no hi ha vorera per la que caminar", + "es": "No, no hay acera por la que caminar", + "cs": "Ne, není tu žádný chodník", + "it": "No, non c'è un marciapiede su cui camminare", + "pl": "Nie, nie ma chodnika, którym można chodzić" } }, { diff --git a/langs/layers/en.json b/langs/layers/en.json index 0f2e3d6b5..af9e542a9 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4218,6 +4218,9 @@ }, "1": { "then": "This is a water tap or water pump with non-drinkable water.
Examples are water taps with rain water to tap water for nearby plants
" + }, + "2": { + "then": "This is a historic, manual water pump where no drinking water can be found" } } }, @@ -4256,8 +4259,72 @@ "question": "Is this drinking water spot still operational?", "render": "The operational status is {operational_status}" }, + "bench-artwork": { + "mappings": { + "0": { + "then": "This drinking water point has an integrated artwork" + }, + "1": { + "then": "This drinking water point does not have an integrated artwork" + }, + "2": { + "then": "This drinking water point probably doesn't have an integrated artwork" + } + }, + "question": "Does this drinking water fountain have an artistic element?", + "questionHint": "E.g. it has an integrated statue or other non-trivial, creative work" + }, + "fee": { + "mappings": { + "0": { + "then": "Free to use" + }, + "1": { + "then": "One needs to pay to use this drinking water point" + } + }, + "question": "Is this drinking water point free to use?" + }, + "opening_hours_24_7": { + "override": { + "+mappings": { + "0": { + "then": "This drinking water fountain is closed this season. As such, the opening hours are not shown." + } + }, + "questionHint": "These are the opening hours if the drinking water fountain is operational." + } + }, "render-closest-drinking-water": { "render": "There is another drinking water fountain at {_closest_other_drinking_water_distance} meters" + }, + "seasonal": { + "mappings": { + "0": { + "then": "This drinking water point is available all around the year" + }, + "1": { + "then": "This drinking water point is only available in summer" + }, + "2": { + "then": "This drinking water point is closed during the winter" + } + }, + "question": "Is this drinking water point available all year round?" + }, + "type": { + "mappings": { + "0": { + "then": "This is a bubbler fountain. A water jet to drink from is sent upwards, typically controlled by a push button." + }, + "1": { + "then": "This is a bottle refill point where the water is sent downwards, typically controlled by a push button or a motion sensor. Drinking directly from the stream might be very hard or impossible." + }, + "2": { + "then": "This is a water tap. The water flows downward and the stream is controlled by a valve or push-button." + } + }, + "question": "What type of drinking water point is this?" } }, "title": { @@ -8979,6 +9046,9 @@ }, "4": { "then": "The surface is concrete" + }, + "5": { + "then": "The surface is fine gravel" } }, "question": "Which is the surface of this sport pitch?", diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 35f8706f0..7e5f66b27 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4092,8 +4092,26 @@ "question": "Is deze drinkwaterkraan nog steeds werkende?", "render": "Deze waterkraan-status is {operational_status}" }, + "bench-artwork": { + "mappings": { + "0": { + "then": "Dit drinkwaterpunt heeft een geintegreerd kunstwerk" + }, + "1": { + "then": "Dit drinkwaterpunt heeft geen geïntegreerd kunstwerk" + }, + "2": { + "then": "Dit drinkwaterpunt heeft waarschijnlijk geen geïntegreerd kunstwerk" + } + }, + "question": "Heeft dit drinkwaterpunt een geintegreerd kunstwerk?", + "questionHint": "Bijvoorbeeld een standbeeld of ander, niet-triviaal kunstwerk" + }, "render-closest-drinking-water": { "render": "Er bevindt zich een ander drinkwaterpunt op {_closest_other_drinking_water_distance} meter" + }, + "type": { + "question": "Wat voor soort drinkwaterpunt is dit?" } }, "title": { @@ -7927,6 +7945,9 @@ }, "4": { "then": "De ondergrond is beton" + }, + "5": { + "then": "De ondergrond bestaat uit grind" } }, "question": "Wat is de ondergrond van dit sportveld?", diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index b1b43a769..97787d023 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -929,6 +929,10 @@ video { margin-right: 0.75rem; } +.mt-12 { + margin-top: 3rem; +} + .mr-12 { margin-right: 3rem; } diff --git a/src/assets/editor-layer-index.json b/src/assets/editor-layer-index.json index a27388a8a..49cf8e29a 100644 --- a/src/assets/editor-layer-index.json +++ b/src/assets/editor-layer-index.json @@ -137,9 +137,10 @@ {"properties":{"name":"Stadt Zürich Luftbild 2013","id":"Zuerich-zh_luftbild2013-wms","url":"https://www.ogd.stadt-zuerich.ch/wms/geoportal/Orthofoto_2013_Stadt_Zuerich___Fruehling?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=OP_2013_STZH.tif&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"text":"Stadt Zürich Open Government Data"},"type":"wms","category":"photo","max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[8.44624,47.44143],[8.44381,47.31555],[8.62895,47.31377],[8.63178,47.43968],[8.44624,47.44143]]],"type":"Polygon"}}, {"properties":{"name":"Stadt Zürich Übersichtsplan","id":"Zuerich-zh_uebersichtsplan-tms","url":"https://mapproxy.osm.ch/tiles/zh_uebersichtsplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","attribution":{"required":false,"text":"Stadt Zürich Open Government Data"},"type":"tms","category":"map","min_zoom":3,"max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[8.45788,47.44582],[8.45745,47.43231],[8.42864,47.43259],[8.42713,47.35161],[8.45609,47.35135],[8.45582,47.33787],[8.48478,47.33762],[8.48418,47.31062],[8.54212,47.31013],[8.54236,47.3236],[8.57152,47.32292],[8.57162,47.33679],[8.6295,47.33628],[8.6318,47.41716],[8.60231,47.41746],[8.60266,47.43096],[8.57362,47.43124],[8.57392,47.44477],[8.45788,47.44582]]],"type":"Polygon"}}, {"properties":{"name":"swisstopo SWISSIMAGE","id":"swisstopo_swissimage","url":"https://wms.geo.admin.ch?LAYERS=ch.swisstopo.swissimage&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Federal Office of Topography swisstopo"},"type":"wms","category":"photo","best":true},"type":"Feature","geometry":{"coordinates":[[[5.95012,46.13048],[5.9669,46.12535],[5.9931,46.13924],[6.0358,46.12984],[6.05582,46.14677],[6.13828,46.13728],[6.18998,46.16083],[6.1935,46.17716],[6.22839,46.19771],[6.29968,46.22229],[6.31605,46.24192],[6.31527,46.2586],[6.29373,46.26902],[6.26889,46.25319],[6.24481,46.27746],[6.25922,46.28922],[6.25462,46.30418],[6.22817,46.31395],[6.25816,46.3575],[6.33795,46.3995],[6.42909,46.412],[6.52094,46.45185],[6.68091,46.44985],[6.81276,46.42411],[6.79581,46.39041],[6.79943,46.38037],[6.76588,46.36335],[6.76564,46.34971],[6.79576,46.31688],[6.85814,46.28152],[6.84857,46.25632],[6.81635,46.23529],[6.79728,46.20575],[6.80522,46.18309],[6.78553,46.16425],[6.7902,46.13778],[6.81289,46.12504],[6.89056,46.12031],[6.87601,46.09643],[6.88274,46.07615],[6.8661,46.04894],[6.89265,46.0383],[6.92715,46.06028],[6.94619,46.0462],[6.98,46.00175],[7.004,45.995],[7.01462,45.97958],[7.00272,45.96702],[7.03035,45.95217],[7.03781,45.92139],[7.057,45.90878],[7.09711,45.85577],[7.12068,45.85521],[7.15564,45.87436],[7.17257,45.85884],[7.19969,45.85636],[7.22215,45.88506],[7.25987,45.88419],[7.29504,45.91546],[7.32302,45.90576],[7.34317,45.90961],[7.38777,45.89276],[7.44795,45.92684],[7.47824,45.93207],[7.48155,45.94843],[7.50149,45.95533],[7.5461,45.95313],[7.55248,45.98191],[7.57329,45.9828],[7.58756,45.96609],[7.66032,45.97164],[7.67694,45.95351],[7.7024,45.94583],[7.70173,45.93254],[7.71862,45.91948],[7.7385,45.92015],[7.75288,45.93512],[7.79697,45.91299],[7.82169,45.92213],[7.86529,45.91233],[7.88297,45.92541],[7.87544,45.93813],[7.88622,45.9708],[7.91245,45.992],[7.98981,45.99146],[8.01827,46.01008],[8.02098,46.03071],[8.04181,46.04344],[8.0292,46.07063],[8.0403,46.09568],[8.11235,46.10816],[8.12232,46.12787],[8.14768,46.13295],[8.16145,46.14614],[8.15623,46.16106],[8.17145,46.18402],[8.14447,46.22843],[8.11883,46.24138],[8.11416,46.25304],[8.09174,46.25773],[8.09284,46.26378],[8.14051,46.29746],[8.16228,46.29143],[8.20207,46.29839],[8.21784,46.3073],[8.23129,46.33186],[8.2675,46.3428],[8.26955,46.3608],[8.28628,46.35935],[8.31773,46.37406],[8.32207,46.39998],[8.30096,46.40914],[8.30912,46.41964],[8.32852,46.42175],[8.36944,46.44769],[8.44458,46.45895],[8.45779,46.44204],[8.4504,46.42361],[8.46114,46.4112],[8.45434,46.38678],[8.46237,46.36267],[8.45747,46.33453],[8.42133,46.299],[8.4477,46.26581],[8.43865,46.24698],[8.45945,46.24039],[8.46694,46.22845],[8.52619,46.21549],[8.56886,46.16128],[8.59174,46.15164],[8.58642,46.14185],[8.60762,46.11825],[8.6442,46.1188],[8.65554,46.10845],[8.71378,46.09274],[8.74045,46.11533],[8.75754,46.09742],[8.78184,46.08975],[8.80782,46.09521],[8.84678,46.07131],[8.84143,46.05424],[8.82366,46.04952],[8.82139,46.0344],[8.7878,46.01068],[8.78015,45.98701],[8.8287,45.98284],[8.86398,45.95728],[8.89022,45.95354],[8.88703,45.93019],[8.91843,45.90303],[8.93071,45.86606],[8.90803,45.84345],[8.90716,45.8276],[8.94969,45.83853],[8.96901,45.82791],[8.98544,45.83215],[8.98986,45.81845],[9.01905,45.81362],[9.03985,45.82056],[9.05684,45.86373],[9.0954,45.90115],[9.06295,45.9249],[9.02733,45.93317],[9.01986,45.96237],[9.00048,45.96965],[9.03491,45.99365],[9.01579,46.03551],[9.02362,46.04763],[9.08143,46.06076],[9.09604,46.08749],[9.07991,46.11618],[9.12508,46.13106],[9.16565,46.16659],[9.18739,46.16665],[9.22866,46.22597],[9.25443,46.23209],[9.25882,46.26494],[9.29023,46.2945],[9.289,46.30883],[9.3058,46.32697],[9.30225,46.35734],[9.28344,46.3697],[9.28654,46.4153],[9.25466,46.43445],[9.25412,46.44392],[9.28397,46.45964],[9.28746,46.49271],[9.36281,46.50281],[9.36556,46.48715],[9.3849,46.47011],[9.41165,46.46243],[9.42981,46.47395],[9.43727,46.49285],[9.45555,46.50043],[9.45511,46.48912],[9.4426,46.48403],[9.45854,46.4695],[9.44795,46.42109],[9.46001,46.39702],[9.4551,46.3743],[9.49209,46.36074],[9.51273,46.32502],[9.54617,46.29851],[9.63354,46.28171],[9.67579,46.29509],[9.71223,46.28775],[9.73092,46.30886],[9.72666,46.3248],[9.73901,46.34544],[9.77755,46.33035],[9.83674,46.35624],[9.87095,46.35828],[9.90553,46.375],[9.9242,46.36154],[9.94926,46.37359],[9.98825,46.34725],[9.97348,46.32274],[9.99116,46.31017],[9.99007,46.283],[10.04906,46.26287],[10.05321,46.25047],[10.03846,46.22718],[10.0694,46.21272],[10.09134,46.22349],[10.1349,46.22075],[10.18301,46.25841],[10.15987,46.29508],[10.12255,46.31688],[10.11182,46.33698],[10.1155,46.34841],[10.13526,46.35941],[10.13452,46.37583],[10.16739,46.38498],[10.17317,46.40822],[10.14633,46.43219],[10.12815,46.4362],[10.08658,46.42628],[10.06614,46.43108],[10.06197,46.44305],[10.04779,46.44639],[10.0609,46.46399],[10.04958,46.48032],[10.06044,46.52203],[10.05066,46.5387],[10.07289,46.54741],[10.08899,46.57165],[10.10621,46.58034],[10.10624,46.60474],[10.12959,46.60082],[10.18803,46.62062],[10.21759,46.61272],[10.23432,46.62839],[10.24995,46.61047],[10.23562,46.59296],[10.24063,46.57253],[10.28256,46.56635],[10.29308,46.54598],[10.32532,46.54616],[10.33765,46.53824],[10.35677,46.55097],[10.3955,46.53955],[10.41582,46.54639],[10.45304,46.52619],[10.47678,46.54012],[10.49829,46.61674],[10.44754,46.64565],[10.40815,46.63985],[10.39157,46.68349],[10.42225,46.70761],[10.42481,46.72086],[10.4114,46.73293],[10.44867,46.75206],[10.4482,46.77235],[10.43329,46.78869],[10.45603,46.80154],[10.47298,46.83515],[10.47307,46.88505],[10.49222,46.91364],[10.49584,46.93845],[10.45833,46.95693],[10.43125,46.96068],[10.43124,46.97886],[10.40302,47.00028],[10.3825,47.00423],[10.34069,46.99166],[10.32182,46.95663],[10.30154,46.94875],[10.30925,46.93022],[10.2353,46.93403],[10.21924,46.89659],[10.2247,46.87087],[10.19226,46.87083],[10.17552,46.8584],[10.10839,46.84623],[10.09085,46.86504],[10.05765,46.86645],[10.05756,46.87906],[10.02063,46.90568],[9.99313,46.90702],[9.97944,46.92025],[9.93956,46.91762],[9.88667,46.93799],[9.87907,46.96301],[9.8988,46.99107],[9.89445,47.00301],[9.8786,47.01032],[9.88678,47.01625],[9.88126,47.02439],[9.85873,47.02765],[9.83663,47.01847],[9.78775,47.04255],[9.72093,47.04838],[9.6824,47.06658],[9.6213,47.05775],[9.619,47.0737],[9.64002,47.08265],[9.64074,47.10227],[9.63014,47.11186],[9.64105,47.12984],[9.62693,47.15403],[9.61055,47.15237],[9.60127,47.16616],[9.57995,47.17558],[9.59121,47.20661],[9.5623,47.22792],[9.57216,47.24545],[9.53931,47.27056],[9.59374,47.31499],[9.61022,47.34847],[9.62617,47.36062],[9.66712,47.36792],[9.6807,47.39034],[9.65853,47.40782],[9.65099,47.43453],[9.66509,47.45395],[9.62565,47.46141],[9.61111,47.47482],[9.59938,47.46717],[9.56828,47.49774],[9.56379,47.5448],[9.49895,47.55556],[9.39725,47.62448],[9.25743,47.66317],[9.17322,47.66001],[9.15322,47.67182],[9.13974,47.66892],[9.09601,47.68375],[9.02305,47.69134],[8.93811,47.66033],[8.89603,47.65264],[8.85957,47.68491],[8.88102,47.69302],[8.8787,47.70608],[8.8219,47.72286],[8.80905,47.74248],[8.76356,47.7201],[8.76412,47.70405],[8.79183,47.69954],[8.78707,47.68101],[8.73356,47.69739],[8.74281,47.71732],[8.71949,47.7332],[8.7481,47.74828],[8.73118,47.76594],[8.71253,47.76977],[8.69489,47.76304],[8.68697,47.78866],[8.6575,47.80492],[8.64109,47.79689],[8.64198,47.77242],[8.63162,47.76476],[8.62273,47.80186],[8.56584,47.8127],[8.55553,47.79147],[8.56921,47.78401],[8.55152,47.78903],[8.51787,47.77813],[8.48673,47.77743],[8.46771,47.76667],[8.44365,47.74006],[8.44791,47.7277],[8.39905,47.70047],[8.41258,47.68489],[8.39933,47.67266],[8.40794,47.66288],[8.45711,47.64828],[8.47221,47.63399],[8.50414,47.64265],[8.53498,47.6418],[8.5554,47.66484],[8.57843,47.65705],[8.60035,47.66568],[8.62226,47.65029],[8.60533,47.65691],[8.5905,47.64577],[8.5985,47.61447],[8.57812,47.60128],[8.57137,47.60265],[8.58086,47.61338],[8.56241,47.62776],[8.51249,47.63774],[8.50152,47.62155],[8.47587,47.6191],[8.45051,47.60397],[8.45444,47.5866],[8.46887,47.57945],[8.46247,47.57654],[8.43144,47.57109],[8.39775,47.58168],[8.38077,47.5712],[8.33152,47.57526],[8.30333,47.59169],[8.29592,47.61273],[8.25853,47.61981],[8.22945,47.61254],[8.20519,47.62554],[8.16154,47.59805],[8.14687,47.60006],[8.13095,47.58795],[8.10579,47.58613],[8.08768,47.56208],[8.06619,47.56892],[8.02093,47.5549],[7.95913,47.5626],[7.9436,47.54851],[7.91678,47.5539],[7.91666,47.57328],[7.89515,47.59141],[7.84218,47.58664],[7.82222,47.59245],[7.79134,47.56098],[7.69263,47.5369],[7.6725,47.53927],[7.65028,47.55568],[7.69128,47.56295],[7.69623,47.57211],[7.68118,47.5875],[7.69823,47.60413],[7.67086,47.59642],[7.64357,47.60123],[7.6185,47.58201],[7.58715,47.59421],[7.5781,47.58112],[7.56339,47.58165],[7.55161,47.56835],[7.49387,47.54282],[7.49164,47.5189],[7.50287,47.49965],[7.48513,47.48653],[7.42777,47.49981],[7.41497,47.47825],[7.44472,47.47005],[7.41133,47.44661],[7.38524,47.43701],[7.33956,47.44567],[7.30134,47.44309],[7.25178,47.42833],[7.23161,47.44403],[7.20071,47.43976],[7.17958,47.44669],[7.19312,47.4807],[7.20943,47.49033],[7.20318,47.49852],[7.16344,47.49448],[7.1279,47.50838],[7.0783,47.49382],[7.02101,47.50895],[6.97881,47.49806],[6.99225,47.45381],[6.96811,47.45136],[6.95973,47.43949],[6.93531,47.43628],[6.93336,47.41025],[6.90806,47.40737],[6.90577,47.38856],[6.87732,47.37429],[6.87286,47.35153],[6.97532,47.35568],[7.01511,47.36719],[7.04346,47.35862],[7.04346,47.34663],[7.05321,47.34302],[7.04673,47.33361],[7.0051,47.32755],[7.0094,47.31461],[6.99432,47.30061],[6.93576,47.28941],[6.94647,47.24458],[6.83572,47.17406],[6.84482,47.15989],[6.80074,47.13403],[6.73624,47.11303],[6.73778,47.09487],[6.69857,47.08563],[6.68496,47.06715],[6.70654,47.05094],[6.69426,47.04203],[6.65467,47.03061],[6.63511,47.00558],[6.61564,46.99609],[6.59171,46.9962],[6.50706,46.97147],[6.49282,46.9779],[6.42715,46.93109],[6.45796,46.8896],[6.45364,46.8528],[6.42452,46.8128],[6.42925,46.79908],[6.45031,46.78735],[6.44531,46.77694],[6.42639,46.76043],[6.39152,46.75219],[6.38401,46.73766],[6.34703,46.71854],[6.27816,46.69432],[6.10453,46.57829],[6.14737,46.54527],[6.06656,46.46673],[6.07968,46.44342],[6.05742,46.41575],[6.09261,46.40539],[6.16249,46.36731],[6.13254,46.34125],[6.1137,46.29918],[6.09612,46.28609],[6.11409,46.24976],[6.10145,46.24379],[6.08999,46.25142],[6.06045,46.24983],[6.04481,46.23761],[6.03073,46.24257],[5.96804,46.21629],[5.95789,46.19505],[5.98733,46.18245],[5.95012,46.13048]]],"type":"Polygon"}}, -{"properties":{"name":"IPR ortofoto LAST (tmsproxy)","id":"IPR-orotofoto-last-tms","url":"https://osm-{switch:a,b,c}.zby.cz/tiles_ipr_last.php/{zoom}/{x}/{y}.jpg","type":"tms","min_zoom":1,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.81232,49.93089],[14.74502,50.25247],[14.12025,50.19882],[14.18755,49.87687],[14.81232,49.93089]]],"type":"Polygon"}}, -{"properties":{"name":"IPR ortofoto Low-Vegetation (tmsproxy)","id":"IPR-orotofoto-vege-tms","url":"https://osm-{switch:a,b,c}.zby.cz/tiles_ipr_vege.php/{zoom}/{x}/{y}.jpg","type":"tms","min_zoom":2,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, -{"properties":{"name":"Praha IPR low-vegetation orthophoto","id":"PrahaIPRlow-vegetationorthophoto","url":"https://giswas1.mepnet.cz/arcgis/services/MAP/mimovegetacni_snimkovani_cache/ImageServer/WMSServer?LAYERS=0&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","type":"wms","category":"historicphoto","min_zoom":1,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, +{"properties":{"name":"Praha IPR latest orthophoto (TMS mirror)","id":"IPR-orotofoto-last-tms","url":"https://osm-{switch:a,b,c}.zby.cz/tiles_ipr_last.php/{zoom}/{x}/{y}.jpg","attribution":{"text":"IPR Praha; OSM CZ","url":"https://iprpraha.cz/"},"type":"tms","category":"photo","min_zoom":2,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, +{"properties":{"name":"Praha IPR low-vegetation orthophoto (TMS mirror)","id":"IPR-orotofoto-vege-tms","url":"https://osm-{switch:a,b,c}.zby.cz/tiles_ipr_vege.php/{zoom}/{x}/{y}.jpg","attribution":{"text":"IPR Praha; OSM CZ","url":"https://iprpraha.cz/"},"type":"tms","category":"photo","min_zoom":2,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, +{"properties":{"name":"Praha IPR latest orthophoto","id":"PrahaIPRlatestorthophoto","url":"https://gs-pub.praha.eu/imgs/services/ort/letecke_snimkovani/ImageServer/WMSServer?FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&LAYERS=0&STYLES=&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","type":"wms","category":"photo","min_zoom":1,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, +{"properties":{"name":"Praha IPR low-vegetation orthophoto","id":"PrahaIPRlow-vegetationorthophoto","url":"https://gs-pub.praha.eu/imgs/services/ort/mimovegetacni_letecke_snimkovani/ImageServer/WMSServer?FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&LAYERS=0&STYLES=&SRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"text":"IPR Praha","url":"https://iprpraha.cz/"},"type":"wms","category":"photo","min_zoom":1,"max_zoom":20,"best":true},"type":"Feature","geometry":{"coordinates":[[[14.30454,49.99538],[14.31604,49.94205],[14.35,49.94508],[14.35384,49.92726],[14.42385,49.93352],[14.42009,49.95097],[14.48865,49.95709],[14.48479,49.97501],[14.55386,49.98117],[14.55012,49.99852],[14.58455,50.00159],[14.5883,49.98424],[14.69168,49.99346],[14.67634,50.06453],[14.71279,50.06777],[14.70115,50.12158],[14.6647,50.11834],[14.661,50.13543],[14.62755,50.13246],[14.61965,50.16895],[14.58543,50.16591],[14.58163,50.18344],[14.40776,50.168],[14.41156,50.15045],[14.37765,50.14744],[14.3738,50.16524],[14.33893,50.16214],[14.34278,50.14434],[14.27368,50.1382],[14.27749,50.12058],[14.2088,50.11447],[14.21289,50.09557],[14.24656,50.09857],[14.25417,50.06336],[14.21987,50.0603],[14.2237,50.04259],[14.258,50.04565],[14.26953,49.99226],[14.30454,49.99538]]],"type":"Polygon"}}, {"properties":{"name":"Berlin/Geoportal TrueDOP20RGB (2020)","id":"Berlin-2020-TrueDOP","url":"https://tiles.codefor.de/berlin-2020-truedop20rgb/{zoom}/{x}/{y}.png","attribution":{"required":true,"text":"Geoportal Berlin/Digitale farbige TrueOrthophotos 2020 (TrueDOP20RGB) (codefor.de mirror)"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[13.05872,52.42427],[13.05951,52.4063],[13.0889,52.40677],[13.08967,52.3888],[13.11905,52.38927],[13.11981,52.3713],[13.14917,52.37177],[13.14842,52.38974],[13.17779,52.3902],[13.20717,52.39064],[13.23654,52.39109],[13.26592,52.39152],[13.2953,52.39195],[13.32467,52.39237],[13.35405,52.39278],[13.35472,52.37481],[13.38409,52.37521],[13.38474,52.35724],[13.4141,52.35764],[13.41474,52.33966],[13.41539,52.32169],[13.44472,52.32208],[13.47405,52.32246],[13.50339,52.32284],[13.53272,52.32321],[13.56206,52.32357],[13.59139,52.32392],[13.62073,52.32427],[13.65007,52.3246],[13.67941,52.32494],[13.67887,52.34291],[13.67833,52.36089],[13.7077,52.36121],[13.70717,52.37919],[13.73655,52.37951],[13.73603,52.39748],[13.76542,52.39779],[13.76492,52.41577],[13.76442,52.43375],[13.76391,52.45172],[13.76341,52.4697],[13.73397,52.46939],[13.73346,52.48736],[13.70401,52.48705],[13.67456,52.48672],[13.67402,52.50469],[13.67348,52.52267],[13.67294,52.54065],[13.64346,52.54031],[13.64291,52.55829],[13.61341,52.55795],[13.61285,52.57592],[13.58334,52.57557],[13.58276,52.59355],[13.55325,52.59319],[13.55265,52.61116],[13.55206,52.62914],[13.55147,52.64711],[13.55087,52.66509],[13.52131,52.66472],[13.5207,52.68269],[13.49113,52.68232],[13.46155,52.68194],[13.43198,52.68155],[13.43262,52.66358],[13.40306,52.66319],[13.3735,52.66278],[13.34394,52.66237],[13.31438,52.66196],[13.31369,52.67993],[13.28412,52.6795],[13.25455,52.67907],[13.25527,52.6611],[13.25598,52.64313],[13.22644,52.64269],[13.19689,52.64225],[13.19763,52.62427],[13.1681,52.62382],[13.16885,52.60585],[13.13933,52.60539],[13.10982,52.60492],[13.11059,52.58695],[13.11136,52.56898],[13.11214,52.55101],[13.11291,52.53304],[13.11368,52.51507],[13.11445,52.4971],[13.11521,52.47913],[13.08578,52.47866],[13.08656,52.46069],[13.08734,52.44272],[13.08812,52.42474],[13.05872,52.42427]]],"type":"Polygon"}}, {"properties":{"name":"Berlin/Geoportal ALKIS","id":"Berlin-Alkis","url":"https://mapproxy.codefor.de/tiles/1.0.0/alkis_30/mercator/{zoom}/{x}/{y}.png","attribution":{"required":true,"text":"Geoportal Berlin/ALKIS Berlin (Amtliches Liegenschaftskatasterinformationssystem) (codefor.de proxy)"},"type":"tms","category":"other","max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[13.29535,52.392],[13.35417,52.39279],[13.38418,52.36617],[13.42861,52.36674],[13.44254,52.38473],[13.53103,52.38581],[13.5313,52.37719],[13.58956,52.37786],[13.61959,52.36012],[13.62038,52.33319],[13.66454,52.33367],[13.66428,52.34287],[13.67876,52.34302],[13.67826,52.36081],[13.70772,52.36111],[13.70722,52.37923],[13.75097,52.39814],[13.75027,52.42468],[13.76454,52.42482],[13.7636,52.46069],[13.73406,52.4604],[13.7188,52.47807],[13.68929,52.48692],[13.65989,52.48661],[13.65912,52.51344],[13.67365,52.51359],[13.67314,52.53139],[13.65822,52.53124],[13.62826,52.55788],[13.5988,52.55755],[13.59798,52.58464],[13.56782,52.59313],[13.53842,52.59279],[13.52345,52.6017],[13.52288,52.61946],[13.53757,52.61964],[13.53643,52.6558],[13.50681,52.65545],[13.50593,52.68261],[13.44682,52.68189],[13.43254,52.67251],[13.43315,52.65458],[13.32953,52.65323],[13.31405,52.67086],[13.26973,52.67025],[13.27041,52.65222],[13.21212,52.63346],[13.18403,52.60593],[13.13972,52.60527],[13.11055,52.59579],[13.11534,52.47934],[13.10073,52.47912],[13.10259,52.43394],[13.07356,52.42447],[13.07431,52.4067],[13.08906,52.40693],[13.11888,52.38921],[13.11926,52.38001],[13.14877,52.38046],[13.14839,52.3897],[13.19241,52.39035],[13.19206,52.39937],[13.29502,52.40083],[13.29535,52.392]]],"type":"Polygon"}}, {"properties":{"name":"Berlin/Geoportal Baumbestand","id":"Berlin-Baumbestand","url":"https://mapproxy.codefor.de/tiles/1.0.0/baumbestand_0_1_3_4_merged/mercator/{zoom}/{x}/{y}.png","attribution":{"required":true,"text":"Geoportal Berlin/Straßen- und Anlagenbaumbestand Berlin (codefor.de proxy)"},"type":"tms","category":"other","max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[13.29535,52.392],[13.35417,52.39279],[13.38418,52.36617],[13.42861,52.36674],[13.44254,52.38473],[13.53103,52.38581],[13.5313,52.37719],[13.58956,52.37786],[13.61959,52.36012],[13.62038,52.33319],[13.66454,52.33367],[13.66428,52.34287],[13.67876,52.34302],[13.67826,52.36081],[13.70772,52.36111],[13.70722,52.37923],[13.75097,52.39814],[13.75027,52.42468],[13.76454,52.42482],[13.7636,52.46069],[13.73406,52.4604],[13.7188,52.47807],[13.68929,52.48692],[13.65989,52.48661],[13.65912,52.51344],[13.67365,52.51359],[13.67314,52.53139],[13.65822,52.53124],[13.62826,52.55788],[13.5988,52.55755],[13.59798,52.58464],[13.56782,52.59313],[13.53842,52.59279],[13.52345,52.6017],[13.52288,52.61946],[13.53757,52.61964],[13.53643,52.6558],[13.50681,52.65545],[13.50593,52.68261],[13.44682,52.68189],[13.43254,52.67251],[13.43315,52.65458],[13.32953,52.65323],[13.31405,52.67086],[13.26973,52.67025],[13.27041,52.65222],[13.21212,52.63346],[13.18403,52.60593],[13.13972,52.60527],[13.11055,52.59579],[13.11534,52.47934],[13.10073,52.47912],[13.10259,52.43394],[13.07356,52.42447],[13.07431,52.4067],[13.08906,52.40693],[13.11888,52.38921],[13.11926,52.38001],[13.14877,52.38046],[13.14839,52.3897],[13.19241,52.39035],[13.19206,52.39937],[13.29502,52.40083],[13.29535,52.392]]],"type":"Polygon"}}, @@ -166,7 +167,10 @@ {"properties":{"name":"Frankfurt am Main Luftbild 2019","id":"Frankfurt-am-Main-2019","url":"https://geowebdienste.frankfurt.de/OD_Luftbilder_2019?REQUEST=GetMap&VERSION=1.3.0&SERVICE=WMS&CRS={proj}&FORMAT=image/jpeg&STYLES=&bbox={bbox}&WIDTH={width}&HEIGHT={height}&LAYERS=opendata_luftbilder_2019","attribution":{"required":true,"text":"Stadtvermessungsamt Frankfurt am Main","url":"https://www.offenedaten.frankfurt.de/dataset/wms-luftbilder-2019-frankfurt-am-main"},"type":"wms","category":"photo"},"type":"Feature","geometry":{"coordinates":[[[8.84647,50.0111],[8.84647,50.22807],[8.46726,50.22807],[8.46726,50.0111],[8.84647,50.0111]]],"type":"Polygon"}}, {"properties":{"name":"Hamburg 20cm (HH LGV DOP20 2022)","id":"hamburg-20cm","url":"https://geodienste.hamburg.de/HH_WMS_DOP?LAYERS=DOP&STYLES=&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung","url":"https://www.hamburg.de/bsw/landesbetrieb-geoinformation-und-vermessung"},"type":"wms","category":"photo","best":true},"type":"Feature","geometry":{"coordinates":[[[[9.76314,53.55521],[9.77434,53.55433],[9.77232,53.54352],[9.77352,53.52796],[9.78105,53.51838],[9.77107,53.52185],[9.76885,53.5053],[9.78203,53.49236],[9.8028,53.49383],[9.80021,53.47372],[9.80663,53.46648],[9.84872,53.44111],[9.86211,53.42942],[9.86885,53.44462],[9.89493,53.45583],[9.90436,53.45707],[9.91704,53.44664],[9.92305,53.43631],[9.90667,53.41596],[9.92552,53.41924],[9.92953,53.42007],[9.9581,53.42708],[9.97873,53.4142],[9.98243,53.41478],[9.99754,53.42546],[10.02294,53.43228],[10.01449,53.44203],[10.03517,53.4469],[10.05155,53.46394],[10.07581,53.45436],[10.1068,53.42658],[10.10949,53.42649],[10.14506,53.41614],[10.16555,53.39933],[10.24155,53.39797],[10.24578,53.40261],[10.25089,53.41024],[10.25598,53.41623],[10.30799,53.43332],[10.32514,53.44979],[10.31223,53.45229],[10.30962,53.44309],[10.29043,53.45512],[10.26592,53.47079],[10.25008,53.47898],[10.2367,53.49629],[10.21828,53.49923],[10.21043,53.51996],[10.18951,53.51148],[10.16919,53.51965],[10.16611,53.52013],[10.16327,53.52185],[10.16874,53.5374],[10.15465,53.53657],[10.15189,53.5417],[10.15942,53.56091],[10.15308,53.56242],[10.148,53.5639],[10.15067,53.56973],[10.15169,53.57619],[10.20117,53.58392],[10.19236,53.59474],[10.18887,53.61316],[10.22202,53.63349],[10.18973,53.63838],[10.19885,53.64675],[10.17153,53.66869],[10.14955,53.67545],[10.14643,53.67588],[10.14473,53.67613],[10.14176,53.67744],[10.14342,53.68057],[10.15829,53.68944],[10.15694,53.70451],[10.1779,53.70992],[10.19369,53.731],[10.16939,53.73896],[10.11908,53.71324],[10.08198,53.72044],[10.0707,53.70996],[10.071,53.69585],[10.0604,53.68833],[10.06925,53.67955],[10.05148,53.67759],[10.04338,53.68198],[10.02282,53.68157],[9.9996,53.68153],[9.98739,53.65072],[9.98492,53.6483],[9.97795,53.64887],[9.95155,53.65065],[9.95024,53.65085],[9.94552,53.65276],[9.93115,53.65262],[9.90678,53.65231],[9.89688,53.63492],[9.89637,53.63122],[9.89356,53.63026],[9.88697,53.6252],[9.88505,53.62199],[9.86931,53.61323],[9.86814,53.6093],[9.85416,53.59805],[9.84498,53.59498],[9.83773,53.59198],[9.81817,53.58591],[9.78993,53.60386],[9.79634,53.6103],[9.7707,53.61607],[9.77129,53.63131],[9.75793,53.61828],[9.73465,53.56536],[9.73047,53.55787],[9.76314,53.55521]]],[[[8.5275,53.90941],[8.52792,53.93577],[8.4826,53.9356],[8.48274,53.90924],[8.5275,53.90941]]]],"type":"MultiPolygon"}}, {"properties":{"name":"Hamburg DK5 (HH LGV DK5 2021)","id":"Hamburg-DK5","url":"https://geodienste.hamburg.de/HH_WMS_DK5?LAYERS=DK5&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/png&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung","url":"https://www.hamburg.de/bsw/landesbetrieb-geoinformation-und-vermessung"},"type":"wms","category":"map"},"type":"Feature","geometry":{"coordinates":[[[[9.76314,53.55521],[9.77434,53.55433],[9.77232,53.54352],[9.77352,53.52796],[9.78105,53.51838],[9.77107,53.52185],[9.76885,53.5053],[9.78203,53.49236],[9.8028,53.49383],[9.80021,53.47372],[9.80663,53.46648],[9.84872,53.44111],[9.86211,53.42942],[9.86885,53.44462],[9.89493,53.45583],[9.90436,53.45707],[9.91704,53.44664],[9.92305,53.43631],[9.90667,53.41596],[9.92552,53.41924],[9.92953,53.42007],[9.9581,53.42708],[9.97873,53.4142],[9.98243,53.41478],[9.99754,53.42546],[10.02294,53.43228],[10.01449,53.44203],[10.03517,53.4469],[10.05155,53.46394],[10.07581,53.45436],[10.1068,53.42658],[10.10949,53.42649],[10.14506,53.41614],[10.16555,53.39933],[10.24155,53.39797],[10.24578,53.40261],[10.25089,53.41024],[10.25598,53.41623],[10.30799,53.43332],[10.32514,53.44979],[10.31223,53.45229],[10.30962,53.44309],[10.29043,53.45512],[10.26592,53.47079],[10.25008,53.47898],[10.2367,53.49629],[10.21828,53.49923],[10.21043,53.51996],[10.18951,53.51148],[10.16919,53.51965],[10.16611,53.52013],[10.16327,53.52185],[10.16874,53.5374],[10.15465,53.53657],[10.15189,53.5417],[10.15942,53.56091],[10.15308,53.56242],[10.148,53.5639],[10.15067,53.56973],[10.15169,53.57619],[10.20117,53.58392],[10.19236,53.59474],[10.18887,53.61316],[10.22202,53.63349],[10.18973,53.63838],[10.19885,53.64675],[10.17153,53.66869],[10.14955,53.67545],[10.14643,53.67588],[10.14473,53.67613],[10.14176,53.67744],[10.14342,53.68057],[10.15829,53.68944],[10.15694,53.70451],[10.1779,53.70992],[10.19369,53.731],[10.16939,53.73896],[10.11908,53.71324],[10.08198,53.72044],[10.0707,53.70996],[10.071,53.69585],[10.0604,53.68833],[10.06925,53.67955],[10.05148,53.67759],[10.04338,53.68198],[10.02282,53.68157],[9.9996,53.68153],[9.98739,53.65072],[9.98492,53.6483],[9.97795,53.64887],[9.95155,53.65065],[9.95024,53.65085],[9.94552,53.65276],[9.93115,53.65262],[9.90678,53.65231],[9.89688,53.63492],[9.89637,53.63122],[9.89356,53.63026],[9.88697,53.6252],[9.88505,53.62199],[9.86931,53.61323],[9.86814,53.6093],[9.85416,53.59805],[9.84498,53.59498],[9.83773,53.59198],[9.81817,53.58591],[9.78993,53.60386],[9.79634,53.6103],[9.7707,53.61607],[9.77129,53.63131],[9.75793,53.61828],[9.73465,53.56536],[9.73047,53.55787],[9.76314,53.55521]]],[[[8.5275,53.90941],[8.52792,53.93577],[8.4826,53.9356],[8.48274,53.90924],[8.5275,53.90941]]]],"type":"MultiPolygon"}}, +{"properties":{"name":"Hesse ALKIS","id":"Hessen-ALKIS","url":"https://www.gds-srv.hessen.de/cgi-bin/lika-services/ogc-free-maps.ows?LAYERS=he_alk&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Geobasisdaten @ Hessisches Landesamt für Bodenmanagement und Geoinformation","url":"https://hvbg.hessen.de"},"type":"wms","category":"map","min_zoom":16,"max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[9.04158,49.49511],[9.06561,49.52721],[9.10595,49.5076],[9.1341,49.51406],[9.10847,49.55019],[9.10767,49.58467],[9.0699,49.61838],[9.10526,49.64118],[9.11041,49.66074],[9.09359,49.69184],[9.13101,49.69695],[9.15642,49.74379],[9.13204,49.79711],[9.08973,49.80149],[9.09067,49.8485],[9.05617,49.85514],[9.03935,49.89309],[9.03265,49.92487],[9.02269,49.98269],[9.05428,49.98986],[9.03308,50.04016],[9.02484,50.04523],[9.00604,50.04722],[8.98261,50.04402],[8.98827,50.06067],[9.00132,50.06937],[9.00578,50.09856],[9.02312,50.11117],[9.0778,50.11463],[9.11522,50.12498],[9.14749,50.10913],[9.14011,50.0946],[9.15316,50.08568],[9.21598,50.14578],[9.37992,50.11552],[9.40361,50.07918],[9.51897,50.08975],[9.53476,50.15887],[9.50798,50.22788],[9.59063,50.21334],[9.65458,50.22481],[9.6738,50.23996],[9.64943,50.25928],[9.71432,50.28133],[9.75054,50.30842],[9.74796,50.36101],[9.76925,50.41989],[9.86506,50.39054],[9.96288,50.41967],[10.04494,50.48351],[10.0458,50.51648],[10.06554,50.55642],[10.04734,50.61375],[10.09369,50.61985],[10.06004,50.67688],[9.9955,50.67753],[9.9519,50.66927],[9.94125,50.66383],[9.96082,50.64097],[9.9416,50.6303],[9.91276,50.64075],[9.88873,50.64271],[9.88564,50.67057],[9.92615,50.69407],[9.91722,50.70907],[9.93851,50.72276],[9.94572,50.75058],[9.9531,50.77197],[9.95619,50.78239],[9.96714,50.82389],[10.0288,50.82589],[10.06536,50.88874],[10.02485,50.91829],[9.98863,50.92457],[10.00151,50.93355],[10.05266,50.93636],[10.06983,50.94383],[10.04373,50.96891],[10.02399,50.98091],[10.04442,51.01116],[10.1433,50.99237],[10.20081,50.99766],[10.2202,51.02714],[10.15755,51.06923],[10.14999,51.08649],[10.2111,51.11613],[10.21505,51.16363],[10.24595,51.18462],[10.18587,51.20817],[10.14107,51.22151],[10.07378,51.23032],[10.08236,51.24354],[10.06176,51.27921],[10.00374,51.28941],[9.95567,51.3083],[9.94898,51.32948],[9.93318,51.35045],[9.9337,51.37778],[9.93387,51.39235],[9.90624,51.42201],[9.79414,51.40981],[9.78744,51.39305],[9.692,51.36749],[9.73509,51.3186],[9.73148,51.29756],[9.67209,51.31946],[9.58214,51.34359],[9.56806,51.3438],[9.5545,51.35892],[9.56944,51.36085],[9.58059,51.37242],[9.56102,51.37741],[9.58162,51.39797],[9.59338,51.3969],[9.63269,51.40295],[9.64514,51.41725],[9.63183,51.45786],[9.64926,51.4678],[9.58969,51.51911],[9.61561,51.51985],[9.62917,51.54666],[9.65046,51.54922],[9.68702,51.56555],[9.69595,51.57792],[9.64102,51.6178],[9.63261,51.63848],[9.61326,51.63526],[9.56755,51.62697],[9.55484,51.64039],[9.54111,51.64157],[9.52429,51.62803],[9.50523,51.62899],[9.49932,51.65916],[9.4388,51.65169],[9.42404,51.63144],[9.36996,51.62803],[9.33134,51.61471],[9.363,51.58944],[9.31383,51.55242],[9.30406,51.51885],[9.27864,51.51526],[9.22045,51.49229],[9.20843,51.46417],[9.17959,51.46941],[9.14852,51.44331],[9.1408,51.45187],[9.09205,51.44737],[9.09428,51.49592],[9.07883,51.50554],[9.03471,51.50778],[9.02063,51.52092],[8.89441,51.48841],[8.88794,51.48149],[8.89333,51.4683],[8.90854,51.46128],[8.91695,51.42876],[8.94249,51.4274],[8.93532,51.39353],[8.88811,51.39492],[8.85498,51.37917],[8.83644,51.39096],[8.79009,51.3931],[8.73516,51.37489],[8.69997,51.3795],[8.67422,51.3721],[8.60899,51.33211],[8.552,51.27846],[8.58976,51.24655],[8.61191,51.24451],[8.6404,51.26063],[8.71765,51.27094],[8.74924,51.17891],[8.69053,51.1366],[8.69018,51.11161],[8.65101,51.09641],[8.61362,51.10363],[8.54238,51.1087],[8.49775,51.08067],[8.49964,51.07387],[8.52144,51.06395],[8.51269,51.05273],[8.50016,51.04075],[8.52728,51.01689],[8.51149,51.00997],[8.45604,50.96675],[8.4478,50.94069],[8.4514,50.9184],[8.43321,50.91959],[8.38652,50.89264],[8.35939,50.86729],[8.30738,50.86513],[8.29382,50.88441],[8.26996,50.88441],[8.1225,50.78814],[8.13563,50.76187],[8.16207,50.73656],[8.13864,50.6957],[8.13023,50.69787],[8.10843,50.67569],[8.10774,50.65316],[8.13452,50.63074],[8.1225,50.60721],[8.151,50.5973],[8.14739,50.58847],[8.10224,50.53591],[8.0377,50.56143],[7.98088,50.5119],[7.97539,50.48176],[8.00646,50.45477],[7.97419,50.43805],[7.95942,50.40928],[7.99084,50.3967],[8.01439,50.39177],[8.01092,50.3816],[8.06053,50.36704],[8.06929,50.33012],[8.10207,50.32135],[8.10053,50.30831],[8.11684,50.27947],[8.1031,50.26466],[8.06122,50.27793],[8.03272,50.27124],[8.01865,50.25741],[8.04989,50.23304],[8.0286,50.22019],[7.99187,50.2415],[7.90381,50.2024],[7.88168,50.18169],[7.88218,50.16656],[7.92355,50.14171],[7.88664,50.11827],[7.86106,50.13147],[7.84469,50.12599],[7.82021,50.08479],[7.80287,50.08645],[7.76802,50.06579],[7.77154,50.05113],[7.85231,50.00548],[7.86209,49.97794],[7.87805,49.97005],[7.89359,49.96856],[7.96363,49.96972],[7.99393,49.97872],[8.04963,50.00178],[8.08285,50.00493],[8.13151,50.0153],[8.15615,50.02528],[8.18722,50.0325],[8.23846,50.02324],[8.26798,50.00917],[8.28215,49.99422],[8.3236,49.96806],[8.34652,49.91509],[8.33605,49.887],[8.3418,49.87168],[8.35218,49.86322],[8.37853,49.85608],[8.37313,49.82392],[8.41364,49.76996],[8.42866,49.76364],[8.47447,49.75984],[8.45467,49.74623],[8.43424,49.7247],[8.37776,49.70961],[8.35304,49.69595],[8.35115,49.6799],[8.36274,49.66002],[8.37467,49.62967],[8.38568,49.61717],[8.40617,49.6037],[8.41776,49.58312],[8.47097,49.58223],[8.48162,49.57354],[8.52333,49.54816],[8.53071,49.53602],[8.54101,49.52599],[8.57534,49.51496],[8.60882,49.52777],[8.62341,49.54181],[8.60539,49.61093],[8.66856,49.62027],[8.68401,49.55985],[8.70152,49.53412],[8.72692,49.51674],[8.81275,49.5057],[8.83352,49.48853],[8.82511,49.47136],[8.79919,49.41075],[8.80297,49.40103],[8.81876,49.39388],[8.85395,49.39321],[8.95351,49.45462],[8.96021,49.49968],[9.04158,49.49511]]],"type":"Polygon"}}, {"properties":{"name":"Hesse DOP20","id":"Hessen-DOP20","url":"https://www.gds-srv.hessen.de/cgi-bin/lika-services/ogc-free-images.ows?LAYERS=he_dop20_rgb&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Geobasisdaten © Hessische Verwaltung für Bodenmanagement und Geoinformation: Digitale Orthophotos","url":"https://hvbg.hessen.de"},"type":"wms","category":"photo","min_zoom":16,"max_zoom":19,"best":true},"type":"Feature","geometry":{"coordinates":[[[9.04158,49.49511],[9.06561,49.52721],[9.10595,49.5076],[9.1341,49.51406],[9.10847,49.55019],[9.10767,49.58467],[9.0699,49.61838],[9.10526,49.64118],[9.11041,49.66074],[9.09359,49.69184],[9.13101,49.69695],[9.15642,49.74379],[9.13204,49.79711],[9.08973,49.80149],[9.09067,49.8485],[9.05617,49.85514],[9.03935,49.89309],[9.03265,49.92487],[9.02269,49.98269],[9.05428,49.98986],[9.03308,50.04016],[9.02484,50.04523],[9.00604,50.04722],[8.98261,50.04402],[8.98827,50.06067],[9.00132,50.06937],[9.00578,50.09856],[9.02312,50.11117],[9.0778,50.11463],[9.11522,50.12498],[9.14749,50.10913],[9.14011,50.0946],[9.15316,50.08568],[9.21598,50.14578],[9.37992,50.11552],[9.40361,50.07918],[9.51897,50.08975],[9.53476,50.15887],[9.50798,50.22788],[9.59063,50.21334],[9.65458,50.22481],[9.6738,50.23996],[9.64943,50.25928],[9.71432,50.28133],[9.75054,50.30842],[9.74796,50.36101],[9.76925,50.41989],[9.86506,50.39054],[9.96288,50.41967],[10.04494,50.48351],[10.0458,50.51648],[10.06554,50.55642],[10.04734,50.61375],[10.09369,50.61985],[10.06004,50.67688],[9.9955,50.67753],[9.9519,50.66927],[9.94125,50.66383],[9.96082,50.64097],[9.9416,50.6303],[9.91276,50.64075],[9.88873,50.64271],[9.88564,50.67057],[9.92615,50.69407],[9.91722,50.70907],[9.93851,50.72276],[9.94572,50.75058],[9.9531,50.77197],[9.95619,50.78239],[9.96714,50.82389],[10.0288,50.82589],[10.06536,50.88874],[10.02485,50.91829],[9.98863,50.92457],[10.00151,50.93355],[10.05266,50.93636],[10.06983,50.94383],[10.04373,50.96891],[10.02399,50.98091],[10.04442,51.01116],[10.1433,50.99237],[10.20081,50.99766],[10.2202,51.02714],[10.15755,51.06923],[10.14999,51.08649],[10.2111,51.11613],[10.21505,51.16363],[10.24595,51.18462],[10.18587,51.20817],[10.14107,51.22151],[10.07378,51.23032],[10.08236,51.24354],[10.06176,51.27921],[10.00374,51.28941],[9.95567,51.3083],[9.94898,51.32948],[9.93318,51.35045],[9.9337,51.37778],[9.93387,51.39235],[9.90624,51.42201],[9.79414,51.40981],[9.78744,51.39305],[9.692,51.36749],[9.73509,51.3186],[9.73148,51.29756],[9.67209,51.31946],[9.58214,51.34359],[9.56806,51.3438],[9.5545,51.35892],[9.56944,51.36085],[9.58059,51.37242],[9.56102,51.37741],[9.58162,51.39797],[9.59338,51.3969],[9.63269,51.40295],[9.64514,51.41725],[9.63183,51.45786],[9.64926,51.4678],[9.58969,51.51911],[9.61561,51.51985],[9.62917,51.54666],[9.65046,51.54922],[9.68702,51.56555],[9.69595,51.57792],[9.64102,51.6178],[9.63261,51.63848],[9.61326,51.63526],[9.56755,51.62697],[9.55484,51.64039],[9.54111,51.64157],[9.52429,51.62803],[9.50523,51.62899],[9.49932,51.65916],[9.4388,51.65169],[9.42404,51.63144],[9.36996,51.62803],[9.33134,51.61471],[9.363,51.58944],[9.31383,51.55242],[9.30406,51.51885],[9.27864,51.51526],[9.22045,51.49229],[9.20843,51.46417],[9.17959,51.46941],[9.14852,51.44331],[9.1408,51.45187],[9.09205,51.44737],[9.09428,51.49592],[9.07883,51.50554],[9.03471,51.50778],[9.02063,51.52092],[8.89441,51.48841],[8.88794,51.48149],[8.89333,51.4683],[8.90854,51.46128],[8.91695,51.42876],[8.94249,51.4274],[8.93532,51.39353],[8.88811,51.39492],[8.85498,51.37917],[8.83644,51.39096],[8.79009,51.3931],[8.73516,51.37489],[8.69997,51.3795],[8.67422,51.3721],[8.60899,51.33211],[8.552,51.27846],[8.58976,51.24655],[8.61191,51.24451],[8.6404,51.26063],[8.71765,51.27094],[8.74924,51.17891],[8.69053,51.1366],[8.69018,51.11161],[8.65101,51.09641],[8.61362,51.10363],[8.54238,51.1087],[8.49775,51.08067],[8.49964,51.07387],[8.52144,51.06395],[8.51269,51.05273],[8.50016,51.04075],[8.52728,51.01689],[8.51149,51.00997],[8.45604,50.96675],[8.4478,50.94069],[8.4514,50.9184],[8.43321,50.91959],[8.38652,50.89264],[8.35939,50.86729],[8.30738,50.86513],[8.29382,50.88441],[8.26996,50.88441],[8.1225,50.78814],[8.13563,50.76187],[8.16207,50.73656],[8.13864,50.6957],[8.13023,50.69787],[8.10843,50.67569],[8.10774,50.65316],[8.13452,50.63074],[8.1225,50.60721],[8.151,50.5973],[8.14739,50.58847],[8.10224,50.53591],[8.0377,50.56143],[7.98088,50.5119],[7.97539,50.48176],[8.00646,50.45477],[7.97419,50.43805],[7.95942,50.40928],[7.99084,50.3967],[8.01439,50.39177],[8.01092,50.3816],[8.06053,50.36704],[8.06929,50.33012],[8.10207,50.32135],[8.10053,50.30831],[8.11684,50.27947],[8.1031,50.26466],[8.06122,50.27793],[8.03272,50.27124],[8.01865,50.25741],[8.04989,50.23304],[8.0286,50.22019],[7.99187,50.2415],[7.90381,50.2024],[7.88168,50.18169],[7.88218,50.16656],[7.92355,50.14171],[7.88664,50.11827],[7.86106,50.13147],[7.84469,50.12599],[7.82021,50.08479],[7.80287,50.08645],[7.76802,50.06579],[7.77154,50.05113],[7.85231,50.00548],[7.86209,49.97794],[7.87805,49.97005],[7.89359,49.96856],[7.96363,49.96972],[7.99393,49.97872],[8.04963,50.00178],[8.08285,50.00493],[8.13151,50.0153],[8.15615,50.02528],[8.18722,50.0325],[8.23846,50.02324],[8.26798,50.00917],[8.28215,49.99422],[8.3236,49.96806],[8.34652,49.91509],[8.33605,49.887],[8.3418,49.87168],[8.35218,49.86322],[8.37853,49.85608],[8.37313,49.82392],[8.41364,49.76996],[8.42866,49.76364],[8.47447,49.75984],[8.45467,49.74623],[8.43424,49.7247],[8.37776,49.70961],[8.35304,49.69595],[8.35115,49.6799],[8.36274,49.66002],[8.37467,49.62967],[8.38568,49.61717],[8.40617,49.6037],[8.41776,49.58312],[8.47097,49.58223],[8.48162,49.57354],[8.52333,49.54816],[8.53071,49.53602],[8.54101,49.52599],[8.57534,49.51496],[8.60882,49.52777],[8.62341,49.54181],[8.60539,49.61093],[8.66856,49.62027],[8.68401,49.55985],[8.70152,49.53412],[8.72692,49.51674],[8.81275,49.5057],[8.83352,49.48853],[8.82511,49.47136],[8.79919,49.41075],[8.80297,49.40103],[8.81876,49.39388],[8.85395,49.39321],[8.95351,49.45462],[8.96021,49.49968],[9.04158,49.49511]]],"type":"Polygon"}}, +{"properties":{"name":"Hesse DTK","id":"Hessen-DTK","url":"https://www.gds-srv.hessen.de/cgi-bin/lika-services/ogc-free-maps.ows?LAYERS=he_dtk&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Geobasisdaten @ Hessisches Landesamt für Bodenmanagement und Geoinformation","url":"https://hvbg.hessen.de"},"type":"wms","category":"map","min_zoom":16,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[9.04158,49.49511],[9.06561,49.52721],[9.10595,49.5076],[9.1341,49.51406],[9.10847,49.55019],[9.10767,49.58467],[9.0699,49.61838],[9.10526,49.64118],[9.11041,49.66074],[9.09359,49.69184],[9.13101,49.69695],[9.15642,49.74379],[9.13204,49.79711],[9.08973,49.80149],[9.09067,49.8485],[9.05617,49.85514],[9.03935,49.89309],[9.03265,49.92487],[9.02269,49.98269],[9.05428,49.98986],[9.03308,50.04016],[9.02484,50.04523],[9.00604,50.04722],[8.98261,50.04402],[8.98827,50.06067],[9.00132,50.06937],[9.00578,50.09856],[9.02312,50.11117],[9.0778,50.11463],[9.11522,50.12498],[9.14749,50.10913],[9.14011,50.0946],[9.15316,50.08568],[9.21598,50.14578],[9.37992,50.11552],[9.40361,50.07918],[9.51897,50.08975],[9.53476,50.15887],[9.50798,50.22788],[9.59063,50.21334],[9.65458,50.22481],[9.6738,50.23996],[9.64943,50.25928],[9.71432,50.28133],[9.75054,50.30842],[9.74796,50.36101],[9.76925,50.41989],[9.86506,50.39054],[9.96288,50.41967],[10.04494,50.48351],[10.0458,50.51648],[10.06554,50.55642],[10.04734,50.61375],[10.09369,50.61985],[10.06004,50.67688],[9.9955,50.67753],[9.9519,50.66927],[9.94125,50.66383],[9.96082,50.64097],[9.9416,50.6303],[9.91276,50.64075],[9.88873,50.64271],[9.88564,50.67057],[9.92615,50.69407],[9.91722,50.70907],[9.93851,50.72276],[9.94572,50.75058],[9.9531,50.77197],[9.95619,50.78239],[9.96714,50.82389],[10.0288,50.82589],[10.06536,50.88874],[10.02485,50.91829],[9.98863,50.92457],[10.00151,50.93355],[10.05266,50.93636],[10.06983,50.94383],[10.04373,50.96891],[10.02399,50.98091],[10.04442,51.01116],[10.1433,50.99237],[10.20081,50.99766],[10.2202,51.02714],[10.15755,51.06923],[10.14999,51.08649],[10.2111,51.11613],[10.21505,51.16363],[10.24595,51.18462],[10.18587,51.20817],[10.14107,51.22151],[10.07378,51.23032],[10.08236,51.24354],[10.06176,51.27921],[10.00374,51.28941],[9.95567,51.3083],[9.94898,51.32948],[9.93318,51.35045],[9.9337,51.37778],[9.93387,51.39235],[9.90624,51.42201],[9.79414,51.40981],[9.78744,51.39305],[9.692,51.36749],[9.73509,51.3186],[9.73148,51.29756],[9.67209,51.31946],[9.58214,51.34359],[9.56806,51.3438],[9.5545,51.35892],[9.56944,51.36085],[9.58059,51.37242],[9.56102,51.37741],[9.58162,51.39797],[9.59338,51.3969],[9.63269,51.40295],[9.64514,51.41725],[9.63183,51.45786],[9.64926,51.4678],[9.58969,51.51911],[9.61561,51.51985],[9.62917,51.54666],[9.65046,51.54922],[9.68702,51.56555],[9.69595,51.57792],[9.64102,51.6178],[9.63261,51.63848],[9.61326,51.63526],[9.56755,51.62697],[9.55484,51.64039],[9.54111,51.64157],[9.52429,51.62803],[9.50523,51.62899],[9.49932,51.65916],[9.4388,51.65169],[9.42404,51.63144],[9.36996,51.62803],[9.33134,51.61471],[9.363,51.58944],[9.31383,51.55242],[9.30406,51.51885],[9.27864,51.51526],[9.22045,51.49229],[9.20843,51.46417],[9.17959,51.46941],[9.14852,51.44331],[9.1408,51.45187],[9.09205,51.44737],[9.09428,51.49592],[9.07883,51.50554],[9.03471,51.50778],[9.02063,51.52092],[8.89441,51.48841],[8.88794,51.48149],[8.89333,51.4683],[8.90854,51.46128],[8.91695,51.42876],[8.94249,51.4274],[8.93532,51.39353],[8.88811,51.39492],[8.85498,51.37917],[8.83644,51.39096],[8.79009,51.3931],[8.73516,51.37489],[8.69997,51.3795],[8.67422,51.3721],[8.60899,51.33211],[8.552,51.27846],[8.58976,51.24655],[8.61191,51.24451],[8.6404,51.26063],[8.71765,51.27094],[8.74924,51.17891],[8.69053,51.1366],[8.69018,51.11161],[8.65101,51.09641],[8.61362,51.10363],[8.54238,51.1087],[8.49775,51.08067],[8.49964,51.07387],[8.52144,51.06395],[8.51269,51.05273],[8.50016,51.04075],[8.52728,51.01689],[8.51149,51.00997],[8.45604,50.96675],[8.4478,50.94069],[8.4514,50.9184],[8.43321,50.91959],[8.38652,50.89264],[8.35939,50.86729],[8.30738,50.86513],[8.29382,50.88441],[8.26996,50.88441],[8.1225,50.78814],[8.13563,50.76187],[8.16207,50.73656],[8.13864,50.6957],[8.13023,50.69787],[8.10843,50.67569],[8.10774,50.65316],[8.13452,50.63074],[8.1225,50.60721],[8.151,50.5973],[8.14739,50.58847],[8.10224,50.53591],[8.0377,50.56143],[7.98088,50.5119],[7.97539,50.48176],[8.00646,50.45477],[7.97419,50.43805],[7.95942,50.40928],[7.99084,50.3967],[8.01439,50.39177],[8.01092,50.3816],[8.06053,50.36704],[8.06929,50.33012],[8.10207,50.32135],[8.10053,50.30831],[8.11684,50.27947],[8.1031,50.26466],[8.06122,50.27793],[8.03272,50.27124],[8.01865,50.25741],[8.04989,50.23304],[8.0286,50.22019],[7.99187,50.2415],[7.90381,50.2024],[7.88168,50.18169],[7.88218,50.16656],[7.92355,50.14171],[7.88664,50.11827],[7.86106,50.13147],[7.84469,50.12599],[7.82021,50.08479],[7.80287,50.08645],[7.76802,50.06579],[7.77154,50.05113],[7.85231,50.00548],[7.86209,49.97794],[7.87805,49.97005],[7.89359,49.96856],[7.96363,49.96972],[7.99393,49.97872],[8.04963,50.00178],[8.08285,50.00493],[8.13151,50.0153],[8.15615,50.02528],[8.18722,50.0325],[8.23846,50.02324],[8.26798,50.00917],[8.28215,49.99422],[8.3236,49.96806],[8.34652,49.91509],[8.33605,49.887],[8.3418,49.87168],[8.35218,49.86322],[8.37853,49.85608],[8.37313,49.82392],[8.41364,49.76996],[8.42866,49.76364],[8.47447,49.75984],[8.45467,49.74623],[8.43424,49.7247],[8.37776,49.70961],[8.35304,49.69595],[8.35115,49.6799],[8.36274,49.66002],[8.37467,49.62967],[8.38568,49.61717],[8.40617,49.6037],[8.41776,49.58312],[8.47097,49.58223],[8.48162,49.57354],[8.52333,49.54816],[8.53071,49.53602],[8.54101,49.52599],[8.57534,49.51496],[8.60882,49.52777],[8.62341,49.54181],[8.60539,49.61093],[8.66856,49.62027],[8.68401,49.55985],[8.70152,49.53412],[8.72692,49.51674],[8.81275,49.5057],[8.83352,49.48853],[8.82511,49.47136],[8.79919,49.41075],[8.80297,49.40103],[8.81876,49.39388],[8.85395,49.39321],[8.95351,49.45462],[8.96021,49.49968],[9.04158,49.49511]]],"type":"Polygon"}}, +{"properties":{"name":"Hesse WebAtlas","id":"Hessen-WebAtlas","url":"https://www.gds-srv.hessen.de/cgi-bin/lika-services/ogc-free-maps.ows?LAYERS=he_pg&STYLES=default&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Geobasisdaten @ Hessisches Landesamt für Bodenmanagement und Geoinformation","url":"https://hvbg.hessen.de"},"type":"wms","category":"map","min_zoom":13,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[9.04158,49.49511],[9.06561,49.52721],[9.10595,49.5076],[9.1341,49.51406],[9.10847,49.55019],[9.10767,49.58467],[9.0699,49.61838],[9.10526,49.64118],[9.11041,49.66074],[9.09359,49.69184],[9.13101,49.69695],[9.15642,49.74379],[9.13204,49.79711],[9.08973,49.80149],[9.09067,49.8485],[9.05617,49.85514],[9.03935,49.89309],[9.03265,49.92487],[9.02269,49.98269],[9.05428,49.98986],[9.03308,50.04016],[9.02484,50.04523],[9.00604,50.04722],[8.98261,50.04402],[8.98827,50.06067],[9.00132,50.06937],[9.00578,50.09856],[9.02312,50.11117],[9.0778,50.11463],[9.11522,50.12498],[9.14749,50.10913],[9.14011,50.0946],[9.15316,50.08568],[9.21598,50.14578],[9.37992,50.11552],[9.40361,50.07918],[9.51897,50.08975],[9.53476,50.15887],[9.50798,50.22788],[9.59063,50.21334],[9.65458,50.22481],[9.6738,50.23996],[9.64943,50.25928],[9.71432,50.28133],[9.75054,50.30842],[9.74796,50.36101],[9.76925,50.41989],[9.86506,50.39054],[9.96288,50.41967],[10.04494,50.48351],[10.0458,50.51648],[10.06554,50.55642],[10.04734,50.61375],[10.09369,50.61985],[10.06004,50.67688],[9.9955,50.67753],[9.9519,50.66927],[9.94125,50.66383],[9.96082,50.64097],[9.9416,50.6303],[9.91276,50.64075],[9.88873,50.64271],[9.88564,50.67057],[9.92615,50.69407],[9.91722,50.70907],[9.93851,50.72276],[9.94572,50.75058],[9.9531,50.77197],[9.95619,50.78239],[9.96714,50.82389],[10.0288,50.82589],[10.06536,50.88874],[10.02485,50.91829],[9.98863,50.92457],[10.00151,50.93355],[10.05266,50.93636],[10.06983,50.94383],[10.04373,50.96891],[10.02399,50.98091],[10.04442,51.01116],[10.1433,50.99237],[10.20081,50.99766],[10.2202,51.02714],[10.15755,51.06923],[10.14999,51.08649],[10.2111,51.11613],[10.21505,51.16363],[10.24595,51.18462],[10.18587,51.20817],[10.14107,51.22151],[10.07378,51.23032],[10.08236,51.24354],[10.06176,51.27921],[10.00374,51.28941],[9.95567,51.3083],[9.94898,51.32948],[9.93318,51.35045],[9.9337,51.37778],[9.93387,51.39235],[9.90624,51.42201],[9.79414,51.40981],[9.78744,51.39305],[9.692,51.36749],[9.73509,51.3186],[9.73148,51.29756],[9.67209,51.31946],[9.58214,51.34359],[9.56806,51.3438],[9.5545,51.35892],[9.56944,51.36085],[9.58059,51.37242],[9.56102,51.37741],[9.58162,51.39797],[9.59338,51.3969],[9.63269,51.40295],[9.64514,51.41725],[9.63183,51.45786],[9.64926,51.4678],[9.58969,51.51911],[9.61561,51.51985],[9.62917,51.54666],[9.65046,51.54922],[9.68702,51.56555],[9.69595,51.57792],[9.64102,51.6178],[9.63261,51.63848],[9.61326,51.63526],[9.56755,51.62697],[9.55484,51.64039],[9.54111,51.64157],[9.52429,51.62803],[9.50523,51.62899],[9.49932,51.65916],[9.4388,51.65169],[9.42404,51.63144],[9.36996,51.62803],[9.33134,51.61471],[9.363,51.58944],[9.31383,51.55242],[9.30406,51.51885],[9.27864,51.51526],[9.22045,51.49229],[9.20843,51.46417],[9.17959,51.46941],[9.14852,51.44331],[9.1408,51.45187],[9.09205,51.44737],[9.09428,51.49592],[9.07883,51.50554],[9.03471,51.50778],[9.02063,51.52092],[8.89441,51.48841],[8.88794,51.48149],[8.89333,51.4683],[8.90854,51.46128],[8.91695,51.42876],[8.94249,51.4274],[8.93532,51.39353],[8.88811,51.39492],[8.85498,51.37917],[8.83644,51.39096],[8.79009,51.3931],[8.73516,51.37489],[8.69997,51.3795],[8.67422,51.3721],[8.60899,51.33211],[8.552,51.27846],[8.58976,51.24655],[8.61191,51.24451],[8.6404,51.26063],[8.71765,51.27094],[8.74924,51.17891],[8.69053,51.1366],[8.69018,51.11161],[8.65101,51.09641],[8.61362,51.10363],[8.54238,51.1087],[8.49775,51.08067],[8.49964,51.07387],[8.52144,51.06395],[8.51269,51.05273],[8.50016,51.04075],[8.52728,51.01689],[8.51149,51.00997],[8.45604,50.96675],[8.4478,50.94069],[8.4514,50.9184],[8.43321,50.91959],[8.38652,50.89264],[8.35939,50.86729],[8.30738,50.86513],[8.29382,50.88441],[8.26996,50.88441],[8.1225,50.78814],[8.13563,50.76187],[8.16207,50.73656],[8.13864,50.6957],[8.13023,50.69787],[8.10843,50.67569],[8.10774,50.65316],[8.13452,50.63074],[8.1225,50.60721],[8.151,50.5973],[8.14739,50.58847],[8.10224,50.53591],[8.0377,50.56143],[7.98088,50.5119],[7.97539,50.48176],[8.00646,50.45477],[7.97419,50.43805],[7.95942,50.40928],[7.99084,50.3967],[8.01439,50.39177],[8.01092,50.3816],[8.06053,50.36704],[8.06929,50.33012],[8.10207,50.32135],[8.10053,50.30831],[8.11684,50.27947],[8.1031,50.26466],[8.06122,50.27793],[8.03272,50.27124],[8.01865,50.25741],[8.04989,50.23304],[8.0286,50.22019],[7.99187,50.2415],[7.90381,50.2024],[7.88168,50.18169],[7.88218,50.16656],[7.92355,50.14171],[7.88664,50.11827],[7.86106,50.13147],[7.84469,50.12599],[7.82021,50.08479],[7.80287,50.08645],[7.76802,50.06579],[7.77154,50.05113],[7.85231,50.00548],[7.86209,49.97794],[7.87805,49.97005],[7.89359,49.96856],[7.96363,49.96972],[7.99393,49.97872],[8.04963,50.00178],[8.08285,50.00493],[8.13151,50.0153],[8.15615,50.02528],[8.18722,50.0325],[8.23846,50.02324],[8.26798,50.00917],[8.28215,49.99422],[8.3236,49.96806],[8.34652,49.91509],[8.33605,49.887],[8.3418,49.87168],[8.35218,49.86322],[8.37853,49.85608],[8.37313,49.82392],[8.41364,49.76996],[8.42866,49.76364],[8.47447,49.75984],[8.45467,49.74623],[8.43424,49.7247],[8.37776,49.70961],[8.35304,49.69595],[8.35115,49.6799],[8.36274,49.66002],[8.37467,49.62967],[8.38568,49.61717],[8.40617,49.6037],[8.41776,49.58312],[8.47097,49.58223],[8.48162,49.57354],[8.52333,49.54816],[8.53071,49.53602],[8.54101,49.52599],[8.57534,49.51496],[8.60882,49.52777],[8.62341,49.54181],[8.60539,49.61093],[8.66856,49.62027],[8.68401,49.55985],[8.70152,49.53412],[8.72692,49.51674],[8.81275,49.5057],[8.83352,49.48853],[8.82511,49.47136],[8.79919,49.41075],[8.80297,49.40103],[8.81876,49.39388],[8.85395,49.39321],[8.95351,49.45462],[8.96021,49.49968],[9.04158,49.49511]]],"type":"Polygon"}}, {"properties":{"name":"Mainz all aerial imageries","id":"mainzallaerialimageries","url":"https://gint.mainz.de/gint1-cgi/mapserv?map=/data/mapbender-int/umn-www/client/a62/luftbild.map","attribution":{"required":true,"text":"Vermessung und Geoinformation Mainz","url":"https://www.mainz.de/vv/oe/100140100000035141.php#tab-infos"},"type":"wms_endpoint","category":"photo","min_zoom":17},"type":"Feature","geometry":{"coordinates":[[[8.10355,49.865],[8.38356,49.865],[8.38356,50.0466],[8.10355,50.0466],[8.10355,49.865]]],"type":"Polygon"}}, {"properties":{"name":"Mainz latest aerial imagery","id":"mainzlatestaerialimagery","url":"https://geodaten.mainz.de/map/service?LAYERS=Orthophoto&STYLES=&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Vermessung und Geoinformation Mainz","url":"https://www.mainz.de/vv/oe/100140100000035141.php#tab-infos"},"type":"wms","category":"photo"},"type":"Feature","geometry":{"coordinates":[[[8.12577,49.9882],[8.12851,49.9722],[8.12714,49.95242],[8.16802,49.9492],[8.17177,49.92458],[8.18318,49.92246],[8.18482,49.89189],[8.19168,49.88438],[8.23837,49.88438],[8.24357,49.88821],[8.26121,49.89058],[8.26867,49.88835],[8.32283,49.88835],[8.3267,49.89722],[8.35167,49.89763],[8.35367,49.90596],[8.35991,49.90868],[8.35991,49.97892],[8.35183,49.98183],[8.35167,49.99527],[8.33946,49.9985],[8.33793,50.00454],[8.32546,50.00754],[8.3242,50.01603],[8.31222,50.01618],[8.30909,50.02398],[8.29593,50.02521],[8.29467,50.04077],[8.29124,50.0421],[8.26929,50.04217],[8.26507,50.04696],[8.15392,50.04696],[8.15222,50.03339],[8.14087,50.03105],[8.13797,50.02457],[8.12783,50.02266],[8.12577,49.9882]]],"type":"Polygon"}}, {"properties":{"name":"Offene Regionalkarte Mecklenburg-Vorpommern (ORKa.MV)","id":"orka.mv","url":"https://www.orka-mv.de/geodienste/orkamv/tiles/1.0.0/orkamv/GLOBAL_WEBMERCATOR/{zoom}/{x}/{y}.png","attribution":{"text":"ORKa.MV","url":"https://www.orka-mv.de/nutzung.html"},"type":"tms","category":"osmbasedmap","min_zoom":12,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[13.32019,54.72212],[12.49001,54.60327],[11.04611,54.03758],[10.73651,53.87637],[10.54746,53.36447],[11.05159,53.14154],[11.31736,53.10208],[12.98593,53.1399],[14.17503,53.21051],[14.45449,53.30557],[14.24626,53.93125],[13.81063,54.51907],[13.5613,54.69996],[13.32019,54.72212]]],"type":"Polygon"}}, @@ -210,7 +214,7 @@ {"properties":{"name":"ICGC - Topogràfic de Catalunya ","id":"ICGC-topo","url":"https://geoserveis.icgc.cat/icc_mapesmultibase/utm/wms/service?LAYERS=topo&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Institut Cartogràfic i Geològic de Catalunya"},"type":"wms","category":"other"},"type":"Feature","geometry":{"coordinates":[[[0.64816,42.69653],[0.65695,42.68887],[0.69162,42.65037],[0.69591,42.62714],[0.70707,42.61918],[0.75806,42.6044],[0.74552,42.55751],[0.71686,42.52513],[0.68699,42.48716],[0.70896,42.43106],[0.72235,42.40381],[0.7172,42.3673],[0.74123,42.32403],[0.73334,42.25559],[0.71154,42.2247],[0.69076,42.15144],[0.68956,42.10102],[0.67789,42.08905],[0.64613,42.02532],[0.58416,41.96766],[0.55344,41.93383],[0.59137,41.92157],[0.59052,41.8826],[0.54932,41.85038],[0.48237,41.80306],[0.47069,41.78872],[0.39705,41.75864],[0.36547,41.72405],[0.32804,41.68817],[0.32375,41.67484],[0.32427,41.6597],[0.34727,41.59606],[0.42108,41.58823],[0.42727,41.56357],[0.44083,41.54507],[0.39482,41.49238],[0.3471,41.48942],[0.33611,41.48235],[0.33955,41.46666],[0.34332,41.43063],[0.33783,41.41351],[0.315,41.39561],[0.35912,41.36702],[0.36976,41.35169],[0.34367,41.33145],[0.34882,41.32204],[0.36238,41.30193],[0.38195,41.27794],[0.37113,41.26181],[0.37079,41.24322],[0.3186,41.22722],[0.29526,41.16392],[0.25062,41.15307],[0.20393,41.13549],[0.19844,41.12644],[0.19895,41.0831],[0.21595,41.0422],[0.23226,41.03171],[0.25801,41.00983],[0.2817,40.96823],[0.28062,40.95514],[0.2738,40.95064],[0.26994,40.9448],[0.2453,40.90923],[0.23603,40.88263],[0.25114,40.87329],[0.24805,40.85563],[0.25715,40.83693],[0.27088,40.82199],[0.23191,40.78691],[0.15638,40.75142],[0.16583,40.72918],[0.23912,40.6973],[0.2829,40.68624],[0.2647,40.65942],[0.2611,40.64457],[0.27826,40.62281],[0.32959,40.60705],[0.39722,40.60001],[0.40203,40.59349],[0.4331,40.57498],[0.4319,40.56546],[0.43499,40.5457],[0.47713,40.53024],[0.61077,40.49239],[0.9391,40.68471],[1.0446,40.98465],[2.12562,41.2353],[2.77469,41.57929],[3.24367,41.88469],[3.33097,42.21861],[3.33679,42.35709],[3.2004,42.35694],[3.17629,42.43562],[3.1684,42.43587],[3.16338,42.43654],[3.16003,42.43565],[3.15771,42.43473],[3.15359,42.4359],[3.13746,42.43777],[3.12355,42.43967],[3.10844,42.43739],[3.09746,42.42827],[3.08266,42.43083],[3.05489,42.45361],[3.04032,42.47583],[3.03034,42.47666],[3.01266,42.46969],[3.00133,42.47412],[2.99075,42.47493],[2.97185,42.47084],[2.9451,42.48326],[2.92975,42.47539],[2.91927,42.45893],[2.90279,42.46045],[2.86983,42.46881],[2.86417,42.46678],[2.85799,42.45677],[2.83795,42.46027],[2.78558,42.41971],[2.77492,42.41456],[2.75448,42.42688],[2.72452,42.42495],[2.67123,42.40522],[2.66796,42.38746],[2.65234,42.39037],[2.64955,42.38615],[2.67036,42.34231],[2.65024,42.34572],[2.57653,42.35984],[2.55377,42.3554],[2.54002,42.33469],[2.50059,42.34459],[2.48342,42.34357],[2.47476,42.35113],[2.46708,42.36169],[2.44169,42.37868],[2.43502,42.39494],[2.38122,42.40277],[2.34538,42.41715],[2.31326,42.42901],[2.25416,42.43992],[2.24505,42.431],[2.21325,42.4249],[2.16755,42.42649],[2.12356,42.41409],[2.10818,42.38265],[2.09035,42.37576],[2.05488,42.35935],[1.99787,42.35982],[1.98035,42.3715],[1.96538,42.38767],[1.95923,42.42428],[1.93604,42.4559],[1.89149,42.45025],[1.88309,42.45999],[1.82417,42.48769],[1.80488,42.491],[1.76206,42.49093],[1.72574,42.50555],[1.70449,42.49191],[1.66786,42.50716],[1.66159,42.49384],[1.65638,42.4698],[1.59656,42.46894],[1.57428,42.45577],[1.56308,42.46173],[1.55837,42.45864],[1.54851,42.43528],[1.51174,42.43142],[1.45,42.44011],[1.44839,42.46045],[1.44359,42.46475],[1.44367,42.4721],[1.4319,42.48901],[1.47071,42.50969],[1.45517,42.53171],[1.45264,42.53954],[1.44024,42.54581],[1.42179,42.54005],[1.42075,42.54783],[1.42822,42.55713],[1.44599,42.568],[1.4441,42.60366],[1.43097,42.61981],[1.41361,42.65762],[1.38789,42.69026],[1.35766,42.72167],[1.3298,42.72572],[1.30787,42.71996],[1.25903,42.72145],[1.23098,42.72999],[1.16532,42.71061],[1.13284,42.74064],[1.13511,42.75069],[1.11373,42.77002],[1.07988,42.78936],[1.01816,42.78832],[0.9601,42.80707],[0.92171,42.79588],[0.90714,42.80513],[0.84959,42.83009],[0.832,42.82956],[0.80944,42.84145],[0.79771,42.84186],[0.78278,42.83796],[0.71465,42.8632],[0.67635,42.85575],[0.65626,42.83846],[0.66369,42.80408],[0.64528,42.78633],[0.64236,42.7823],[0.65798,42.77209],[0.63843,42.75414],[0.67514,42.72545],[0.66553,42.72041],[0.67789,42.70742],[0.66925,42.69249],[0.64816,42.69653]]],"type":"Polygon"}}, {"properties":{"name":"PNOA Spain","id":"PNOA-Spain-TMS","url":"https://tms-pnoa-ma.idee.es/1.0.0/pnoa-ma/{zoom}/{x}/{-y}.jpeg","attribution":{"required":true,"text":"PNOA"},"type":"tms","category":"photo","max_zoom":20,"best":true},"type":"Feature","geometry":{"coordinates":[[[[-17.88913,27.85905],[-17.99065,27.85675],[-18.03868,27.76558],[-18.11464,27.76379],[-18.11546,27.78636],[-18.1661,27.78516],[-18.16349,27.69492],[-18.08898,27.69634],[-18.08734,27.67387],[-18.03641,27.67537],[-18.03501,27.63026],[-17.959,27.6324],[-17.86033,27.7926],[-17.86303,27.83688],[-17.8884,27.83649],[-17.88913,27.85905]]],[[[-15.75328,28.08143],[-15.7783,28.03632],[-15.82911,28.03558],[-15.82895,27.99066],[-15.8542,27.99018],[-15.85374,27.90089],[-15.80167,27.81105],[-15.70075,27.74335],[-15.62415,27.74199],[-15.62361,27.72134],[-15.54771,27.72161],[-15.52277,27.76678],[-15.47188,27.76665],[-15.47181,27.78939],[-15.421,27.78797],[-15.39598,27.83474],[-15.37057,27.83521],[-15.3708,27.92524],[-15.34548,27.92544],[-15.34578,28.01532],[-15.37065,28.01532],[-15.37103,28.03802],[-15.39644,28.03836],[-15.39728,28.19614],[-15.45016,28.19614],[-15.44978,28.15075],[-15.49874,28.15041],[-15.49897,28.1728],[-15.72826,28.17186],[-15.72788,28.08157],[-15.75328,28.08143]]],[[[-17.08208,28.13518],[-17.18579,28.22388],[-17.33846,28.2213],[-17.33756,28.17637],[-17.36297,28.17572],[-17.36038,28.06398],[-17.30867,28.01923],[-17.25785,28.01997],[-17.25768,27.99784],[-17.23199,27.99804],[-17.23211,28.02037],[-17.15633,28.02146],[-17.13154,28.06681],[-17.08084,28.068],[-17.08208,28.13518]]],[[[-16.44571,28.49113],[-16.52143,28.42261],[-16.87807,28.39542],[-16.87767,28.37293],[-16.92866,28.37219],[-16.92782,28.32758],[-16.90239,28.32793],[-16.90151,28.28277],[-16.87608,28.28322],[-16.87565,28.26055],[-16.85028,28.26079],[-16.8487,28.17075],[-16.82317,28.17087],[-16.8224,28.1259],[-16.7707,28.08161],[-16.74534,28.08181],[-16.7447,28.03679],[-16.7191,28.03714],[-16.71842,27.99192],[-16.61681,27.99305],[-16.61684,28.01532],[-16.51533,28.01648],[-16.4151,28.13113],[-16.41584,28.19761],[-16.34083,28.2893],[-16.34208,28.37951],[-16.31631,28.38019],[-16.31675,28.40176],[-16.26586,28.403],[-16.26535,28.44761],[-16.23858,28.44847],[-16.16475,28.49386],[-16.16481,28.51612],[-16.09934,28.51638],[-16.09951,28.5925],[-16.1278,28.59218],[-16.12793,28.60782],[-16.19162,28.60684],[-16.19125,28.58372],[-16.3446,28.58221],[-16.34433,28.55976],[-16.42092,28.55884],[-16.42059,28.53627],[-16.44625,28.53597],[-16.44571,28.49113]]],[[[-14.21537,28.33903],[-14.21688,28.22788],[-14.41575,28.11561],[-14.52244,28.11841],[-14.52156,28.04678],[-14.49593,28.04585],[-14.49628,28.06826],[-14.44666,28.0658],[-14.44578,28.04698],[-14.33197,28.03687],[-14.29132,28.04524],[-14.21472,28.11189],[-14.21537,28.15781],[-14.13866,28.15791],[-14.13871,28.17999],[-14.03696,28.17958],[-13.98564,28.22357],[-13.91582,28.22414],[-13.83151,28.39702],[-13.82885,28.53847],[-13.80339,28.53842],[-13.80258,28.6519],[-13.82786,28.6518],[-13.82757,28.71935],[-13.8013,28.71899],[-13.80007,28.78793],[-13.82896,28.78798],[-13.82902,28.76643],[-13.95617,28.76659],[-13.95652,28.74494],[-14.03358,28.72267],[-14.11151,28.4748],[-14.16417,28.45283],[-14.21537,28.33903]]],[[[-17.9424,28.87261],[-18.02241,28.80384],[-18.02125,28.74819],[-17.89395,28.52255],[-17.88463,28.44606],[-17.80601,28.4469],[-17.80861,28.4925],[-17.78316,28.49366],[-17.78331,28.54167],[-17.76225,28.5592],[-17.75197,28.58337],[-17.74573,28.61656],[-17.74579,28.67435],[-17.75708,28.67413],[-17.75744,28.69318],[-17.71293,28.73037],[-17.71398,28.76497],[-17.73949,28.76422],[-17.74127,28.832],[-17.76698,28.83122],[-17.76759,28.85378],[-17.89033,28.85151],[-17.89118,28.87371],[-17.9424,28.87261]]],[[[-13.85025,29.01659],[-13.85182,28.98343],[-13.85244,28.91486],[-13.90131,28.89245],[-13.9024,28.84698],[-13.80066,28.84566],[-13.80093,28.82311],[-13.77569,28.82305],[-13.69729,28.88982],[-13.69729,28.91277],[-13.60725,28.9118],[-13.43886,29.00024],[-13.43746,29.13513],[-13.4117,29.13499],[-13.41056,29.22298],[-13.45928,29.25559],[-13.45974,29.2942],[-13.50913,29.29456],[-13.51006,29.31635],[-13.56354,29.31729],[-13.56406,29.27138],[-13.53892,29.2712],[-13.53897,29.25004],[-13.56613,29.25013],[-13.5666,29.203],[-13.51565,29.20223],[-13.51565,29.18206],[-13.5398,29.18278],[-13.54089,29.13753],[-13.65782,29.13685],[-13.71322,29.09351],[-13.76634,29.09345],[-13.85025,29.01659]]],[[[1.50355,38.72532],[1.48133,38.91551],[1.55189,38.92544],[1.56673,38.95666],[1.64874,38.95833],[1.64799,38.99907],[1.73217,38.99936],[1.73147,39.04417],[1.64895,39.04319],[1.64816,39.12764],[1.39486,39.12657],[1.39544,39.08642],[1.22811,39.08526],[1.22911,39.0029],[1.14487,39.0018],[1.14528,38.832],[1.31136,38.83316],[1.31219,38.79065],[1.39469,38.79162],[1.39519,38.75296],[1.31128,38.75193],[1.31259,38.62388],[1.6489,38.62511],[1.64807,38.71115],[1.58456,38.71012],[1.58116,38.70054],[1.54915,38.70028],[1.51972,38.70921],[1.50355,38.72532]]],[[[2.31192,39.54179],[2.31223,39.49934],[2.43902,39.49934],[2.43871,39.48469],[2.43933,39.41611],[2.54507,39.41667],[2.54528,39.49942],[2.64538,39.49966],[2.64569,39.45774],[2.72885,39.45814],[2.72874,39.33342],[2.97904,39.3335],[2.97986,39.25015],[3.08302,39.24994],[3.31462,39.37855],[3.31506,39.47846],[3.48035,39.5959],[3.48148,39.79318],[3.14844,39.79357],[3.14823,39.83316],[3.23129,39.83292],[3.23139,40.00198],[3.14608,40.00198],[3.14566,39.96005],[2.92704,39.96016],[2.34601,39.62709],[2.22835,39.62606],[2.22907,39.541],[2.31192,39.54179]]],[[[-9.21855,42.90163],[-9.14661,42.77503],[-9.08834,42.72696],[-9.03655,42.73066],[-9.1092,42.57511],[-8.89106,41.82289],[-8.60704,42.03405],[-8.36762,42.05575],[-8.24848,42.1008],[-8.12933,42.03488],[-8.25185,41.90786],[-8.13045,41.78058],[-7.95398,41.84593],[-7.42569,41.78477],[-7.16829,41.87188],[-7.13345,41.94048],[-6.62988,41.91121],[-6.54783,41.85597],[-6.58717,41.68832],[-6.51523,41.64129],[-6.31628,41.64465],[-6.21737,41.5791],[-6.56244,41.26303],[-6.64112,41.26556],[-6.76814,41.13871],[-6.80186,41.03959],[-6.9536,41.03704],[-6.83783,40.87576],[-6.85356,40.60664],[-6.86818,40.44516],[-6.8086,40.34501],[-7.01767,40.26615],[-7.04128,40.13479],[-6.88616,40.02299],[-6.92213,39.87909],[-6.99519,39.81954],[-7.05027,39.67522],[-7.55271,39.67954],[-7.51449,39.58865],[-7.3279,39.45599],[-7.33689,39.35351],[-7.25596,39.28133],[-7.24472,39.19689],[-7.15255,39.16029],[-7.15368,39.09577],[-7.00081,39.08879],[-6.96934,39.01983],[-7.06151,38.90796],[-7.04352,38.87297],[-7.26383,38.73807],[-7.34027,38.44024],[-7.08062,38.15708],[-6.96147,38.20125],[-6.99632,38.10756],[-7.0143,38.02438],[-7.11771,38.05536],[-7.15368,38.01552],[-7.26833,37.98895],[-7.31666,37.83997],[-7.4249,37.75992],[-7.45013,37.66958],[-7.52196,37.57237],[-7.51916,37.52292],[-7.50197,37.51641],[-7.4647,37.45305],[-7.46963,37.40758],[-7.4481,37.39094],[-7.44597,37.33261],[-7.43805,37.2452],[-7.42492,37.23505],[-7.42029,37.21183],[-7.40832,37.16822],[-7.37535,37.15354],[-7.26474,37.18435],[-7.04264,37.18507],[-6.87448,37.10838],[-6.62989,37.0194],[-6.49052,36.91738],[-6.41588,36.79939],[-6.47433,36.74897],[-6.40419,36.6235],[-6.32146,36.58163],[-6.33585,36.53106],[-6.23154,36.37701],[-6.15061,36.28646],[-6.07752,36.22241],[-6.03573,36.1781],[-5.99834,36.1645],[-5.94003,36.16556],[-5.93848,36.12215],[-5.85668,36.12421],[-5.85506,36.03856],[-5.68996,36.04053],[-5.68886,36.00365],[-5.43532,36.00344],[-5.43658,36.03889],[-5.35161,36.04014],[-5.35248,36.12247],[-5.26809,36.12418],[-5.28411,36.19702],[-5.16995,36.35135],[-4.9188,36.45313],[-4.65712,36.44042],[-4.37435,36.66333],[-3.72804,36.69291],[-3.46108,36.65488],[-3.09402,36.71263],[-2.92015,36.66756],[-2.68129,36.65911],[-2.37219,36.78018],[-2.21588,36.66192],[-2.06835,36.69291],[-1.85408,36.91229],[-1.6767,37.27652],[-1.44089,37.39037],[-1.33832,37.52867],[-1.11071,37.51641],[-0.91963,37.53758],[-0.71939,37.58784],[-0.66415,37.62315],[-0.68831,37.734],[-0.72158,37.78306],[-0.73237,37.88107],[-0.68111,37.94562],[-0.63705,37.96122],[-0.61367,38.11986],[-0.584,38.17219],[-0.45451,38.14886],[-0.42933,38.16583],[-0.48238,38.19481],[-0.50487,38.28309],[-0.45091,38.33108],[-0.38347,38.33813],[-0.37987,38.39312],[-0.27197,38.47624],[-0.05705,38.52691],[-0.0022,38.60706],[0.09581,38.61338],[0.25587,38.72642],[0.23429,38.79864],[0.12189,38.87218],[0.00949,38.88268],[-0.11101,38.97222],[-0.21352,39.15585],[-0.18564,39.17746],[-0.28636,39.33343],[-0.29085,39.50363],[-0.18474,39.63117],[-0.09392,39.81169],[0.01039,39.89522],[0.07513,40.01447],[0.16415,40.06472],[0.26756,40.19192],[0.43392,40.37576],[0.55801,40.55022],[0.66502,40.53587],[0.87813,40.67514],[0.9114,40.73376],[0.75854,40.81956],[1.08585,41.04849],[1.17937,41.04646],[1.3763,41.11627],[1.86008,41.22322],[2.16492,41.29893],[2.26293,41.42716],[2.78358,41.63718],[3.06054,41.76474],[3.19452,41.85589],[3.24668,41.95294],[3.23055,42.126],[3.14759,42.12606],[3.14759,42.2073],[3.31397,42.20702],[3.31389,42.29084],[3.39739,42.29009],[3.39785,42.33404],[3.31412,42.33399],[3.31415,42.37604],[3.23049,42.37644],[3.23078,42.45934],[3.06388,42.45915],[3.06388,42.50085],[2.81126,42.50104],[2.81133,42.45961],[2.64448,42.45924],[2.64479,42.37626],[2.48098,42.37594],[2.48048,42.41797],[2.39768,42.41784],[2.39693,42.45994],[2.06456,42.45902],[2.06386,42.50164],[1.73164,42.50118],[1.73041,42.54342],[1.64328,42.54245],[1.64436,42.50203],[1.4813,42.50107],[1.48061,42.71034],[1.41137,42.70939],[1.36326,42.74155],[1.17532,42.73429],[1.10878,42.79898],[0.9676,42.81811],[0.71492,42.88272],[0.64118,42.85767],[0.62769,42.7224],[0.44875,42.71447],[0.36422,42.74287],[0.30218,42.71777],[0.18618,42.7541],[-0.03143,42.71249],[-0.14563,42.81086],[-0.31648,42.86558],[-0.42889,42.82009],[-0.50442,42.84845],[-0.55118,42.82207],[-0.69685,42.90314],[-0.71484,42.96108],[-0.7562,42.98213],[-0.94234,42.9749],[-1.00619,43.00778],[-1.19232,43.06496],[-1.27955,43.07744],[-1.23549,43.13325],[-1.30203,43.13522],[-1.36407,43.11159],[-1.37307,43.05117],[-1.41983,43.06036],[-1.44231,43.08336],[-1.37037,43.1713],[-1.35688,43.23815],[-1.36677,43.27614],[-1.47799,43.31284],[-1.56305,43.31338],[-1.56359,43.29212],[-1.60344,43.29266],[-1.60299,43.31295],[-1.64498,43.31332],[-1.64467,43.33372],[-1.68811,43.33413],[-1.68904,43.31291],[-1.72259,43.31318],[-1.71135,43.33125],[-1.71005,43.37569],[-1.77005,43.37605],[-1.7698,43.39644],[-1.85528,43.39725],[-1.9854,43.3563],[-2.30462,43.31706],[-2.74524,43.47551],[-2.93857,43.46246],[-3.1083,43.38163],[-3.56128,43.54236],[-3.74,43.48693],[-3.80295,43.51954],[-4.18399,43.42492],[-4.61562,43.4192],[-4.90899,43.48367],[-5.17875,43.49916],[-5.28553,43.56191],[-5.60363,43.57087],[-5.85204,43.6799],[-6.12293,43.57901],[-6.24882,43.6075],[-7.19975,43.58308],[-7.31889,43.67827],[-7.66284,43.80982],[-7.83591,43.73743],[-7.85605,43.79146],[-7.9172,43.78264],[-7.99921,43.7234],[-8.06467,43.72392],[-8.27761,43.57088],[-8.33444,43.57974],[-8.36033,43.46342],[-8.36105,43.41118],[-8.45745,43.39184],[-8.52507,43.36465],[-8.52435,43.3364],[-8.55097,43.32332],[-8.60996,43.3296],[-8.70635,43.305],[-8.78548,43.31914],[-8.82217,43.37354],[-8.87613,43.37407],[-8.8639,43.32908],[-8.92936,43.32699],[-8.93727,43.30553],[-8.99986,43.29558],[-8.99842,43.24477],[-9.03367,43.24267],[-9.06748,43.19916],[-9.14733,43.21018],[-9.2315,43.17032],[-9.25236,43.10417],[-9.30991,43.06004],[-9.27898,42.9822],[-9.30991,42.93113],[-9.2761,42.86051],[-9.21855,42.90163]]],[[[4.0628,40.12722],[4.06242,40.08499],[3.81287,40.08529],[3.81204,40.04344],[3.72908,40.0438],[3.72862,39.95842],[3.81266,39.9576],[3.81228,39.91644],[3.9609,39.91598],[4.19381,39.79131],[4.31503,39.79058],[4.31599,39.83293],[4.39874,39.83204],[4.39737,39.91858],[4.3158,39.91933],[4.31619,40.0434],[4.2319,40.04436],[4.23248,40.08478],[4.14915,40.08611],[4.14906,40.12552],[4.0628,40.12722]]]],"type":"MultiPolygon"}}, {"properties":{"name":"geoEuskadiren Ortoargazkiak","id":"geoEuskadi-ORTO","url":"https://www.geo.euskadi.eus/WMS_ORTOARGAZKIAK?LAYERS=ORTO_EGUNERATUENA_MAS_ACTUALIZADA&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"Eusko Jaurlaritza / Gobierno Vasco. geoEuskadi"},"type":"wms","category":"photo","best":true},"type":"Feature","geometry":{"coordinates":[[[-3.11024,43.43771],[-3.15462,43.35277],[-3.15239,43.34796],[-3.15535,43.34091],[-3.15823,43.30694],[-3.19462,43.30082],[-3.21299,43.28858],[-3.26311,43.29807],[-3.29573,43.30269],[-3.33418,43.30382],[-3.34705,43.29782],[-3.34534,43.27958],[-3.37641,43.27658],[-3.39392,43.26558],[-3.39958,43.25258],[-3.41675,43.2527],[-3.45434,43.2372],[-3.44679,43.22019],[-3.43602,43.20608],[-3.43941,43.19179],[-3.43529,43.16838],[-3.41949,43.12993],[-3.38963,43.13469],[-3.25316,43.19316],[-3.22792,43.17151],[-3.21608,43.17076],[-3.18707,43.16638],[-3.16887,43.17514],[-3.14569,43.16763],[-3.16544,43.15536],[-3.17059,43.14546],[-3.18672,43.12141],[-3.18157,43.11301],[-3.15239,43.10086],[-3.16183,43.07215],[-3.14449,43.06287],[-3.15291,43.03188],[-3.18226,43.02962],[-3.17986,43.01783],[-3.1481,43.00314],[-3.08922,42.99812],[-3.0451,42.98092],[-3.0518,42.97162],[-3.01866,42.94901],[-2.99292,42.94034],[-3.03103,42.90967],[-3.09076,42.90489],[-3.10175,42.91683],[-3.14535,42.93908],[-3.20578,42.95316],[-3.22775,42.95291],[-3.24492,42.94411],[-3.28251,42.90389],[-3.29092,42.88376],[-3.28491,42.8698],[-3.22809,42.82562],[-3.13557,42.78545],[-3.15531,42.75332],[-3.1299,42.75332],[-3.08201,42.75432],[-3.04047,42.73579],[-2.98142,42.69972],[-2.96459,42.70565],[-2.93232,42.70616],[-2.93301,42.69859],[-2.92262,42.6996],[-2.9185,42.69695],[-2.90442,42.69259],[-2.90468,42.68635],[-2.8985,42.6765],[-2.90108,42.6731],[-2.90108,42.66729],[-2.89807,42.65366],[-2.89069,42.6476],[-2.87129,42.63819],[-2.86331,42.63712],[-2.85627,42.6368],[-2.844,42.62954],[-2.84512,42.62404],[-2.84966,42.61741],[-2.84881,42.61527],[-2.84451,42.61078],[-2.84254,42.60674],[-2.82349,42.61078],[-2.82512,42.60017],[-2.84254,42.58184],[-2.83825,42.56863],[-2.82529,42.55327],[-2.81877,42.55352],[-2.79825,42.56535],[-2.77508,42.57976],[-2.76169,42.61678],[-2.73903,42.61767],[-2.71397,42.60048],[-2.68702,42.59315],[-2.69028,42.56964],[-2.70933,42.5164],[-2.69543,42.51374],[-2.64856,42.48083],[-2.63792,42.48349],[-2.62316,42.49299],[-2.60084,42.49349],[-2.6053,42.48071],[-2.60153,42.47159],[-2.58522,42.46919],[-2.57183,42.48691],[-2.56857,42.49134],[-2.55707,42.48248],[-2.52909,42.47982],[-2.52497,42.48526],[-2.47707,42.48501],[-2.47004,42.49109],[-2.43519,42.48792],[-2.42133,42.48817],[-2.41845,42.48849],[-2.4218,42.50969],[-2.39021,42.51526],[-2.39468,42.54492],[-2.38704,42.54783],[-2.38729,42.56364],[-2.39348,42.59941],[-2.41897,42.60907],[-2.42455,42.60693],[-2.4509,42.57318],[-2.45974,42.58924],[-2.48772,42.59183],[-2.46034,42.62777],[-2.45253,42.63371],[-2.41605,42.66003],[-2.38936,42.65593],[-2.38395,42.63282],[-2.34447,42.63206],[-2.28979,42.65056],[-2.28344,42.65845],[-2.29185,42.67884],[-2.30824,42.67991],[-2.30988,42.70912],[-2.31546,42.73434],[-2.3043,42.7339],[-2.27134,42.74115],[-2.25932,42.74695],[-2.27468,42.78671],[-2.26576,42.79332],[-2.2316,42.83481],[-2.23005,42.84344],[-2.23872,42.86615],[-2.23941,42.88565],[-2.23658,42.89596],[-2.23065,42.9311],[-2.16019,42.93418],[-2.11676,42.93858],[-2.09873,42.94813],[-2.0886,42.96836],[-2.04844,42.97376],[-2.03556,42.97979],[-2.02732,42.98795],[-2.02372,43.00088],[-2.03453,43.02737],[-2.02578,43.02987],[-2.01428,43.05133],[-2.01736,43.0645],[-1.96741,43.08356],[-1.95213,43.09594],[-1.94617,43.09694],[-1.93626,43.10546],[-1.92029,43.11583],[-1.89969,43.13557],[-1.90175,43.14634],[-1.91497,43.16957],[-1.90776,43.20855],[-1.88201,43.20468],[-1.87231,43.21049],[-1.85987,43.21049],[-1.82262,43.22801],[-1.7924,43.24564],[-1.7882,43.27702],[-1.77644,43.28558],[-1.76253,43.28458],[-1.72747,43.29304],[-1.72639,43.29911],[-1.72863,43.29782],[-1.73545,43.31262],[-1.74054,43.31681],[-1.7368,43.32162],[-1.73698,43.3241],[-1.73794,43.32596],[-1.73661,43.33042],[-1.7412,43.33197],[-1.74462,43.33184],[-1.75024,43.33183],[-1.75253,43.33404],[-1.75099,43.33592],[-1.7523,43.33954],[-1.75307,43.34135],[-1.75438,43.3423],[-1.75747,43.34405],[-1.75884,43.34431],[-1.76037,43.34434],[-1.76221,43.34441],[-1.76532,43.34341],[-1.76648,43.34309],[-1.7679,43.34263],[-1.76938,43.34242],[-1.77191,43.34266],[-1.77416,43.34353],[-1.77609,43.34437],[-1.77665,43.34537],[-1.77674,43.34617],[-1.77697,43.34742],[-1.77753,43.34818],[-1.77845,43.34826],[-1.78009,43.34848],[-1.78118,43.34842],[-1.78309,43.34882],[-1.78438,43.34951],[-1.78622,43.35083],[-1.78691,43.35208],[-1.7867,43.35398],[-1.77851,43.36299],[-1.78802,43.36918],[-1.78946,43.37277],[-1.78906,43.37611],[-1.76571,43.38409],[-1.8091,43.40669],[-2.7502,43.4637],[-3.11024,43.43771]]],"type":"Polygon"}}, -{"properties":{"name":"IDEIB - Ortofoto 2021 (SITIBSA - scne.es)","id":"IDEIB","url":"https://ideib.caib.es/geoserveis/services/imatges/GOIB_Orto_IB/MapServer/WmsServer?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"Infraestructura de Dades Espacials de les Illes Balears"},"type":"wms","category":"photo","best":true},"type":"Feature","geometry":{"coordinates":[[[1.20849,38.05675],[3.28491,38.90386],[4.93835,39.71987],[4.28466,40.7098],[1.8457,40.02341],[0.61523,39.05332],[1.20849,38.05675]]],"type":"Polygon"}}, +{"properties":{"name":"IDEIB - Ortofoto més recent de les Illes Balears","id":"IDEIB","url":"https://ideib.caib.es/geoserveis/services/imatges/GOIB_Orto_IB/MapServer/WmsServer?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=0&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"Infraestructura de Dades Espacials de les Illes Balears"},"type":"wms","category":"photo","best":true},"type":"Feature","geometry":{"coordinates":[[[1.20849,38.05675],[3.28491,38.90386],[4.93835,39.71987],[4.28466,40.7098],[1.8457,40.02341],[0.61523,39.05332],[1.20849,38.05675]]],"type":"Polygon"}}, {"properties":{"name":"Helsinki region orthophoto","id":"hri-orto","url":"https://kartta.hsy.fi/geoserver/ows?LAYERS=taustakartat_ja_aluejaot:Ortoilmakuva_2017&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"© Espoon, Helsingin ja Vantaan kaupungit, Kirkkonummen ja Nurmijärven kunnat sekä HSL ja HSY","url":"https://hri.fi/data/en_GB/dataset/paakaupunkiseudun-ortokuva-2017"},"type":"wms","category":"photo","max_zoom":19,"best":true},"type":"Feature","geometry":{"coordinates":[[[24.26948,59.8593],[25.19577,60.08813],[25.27954,60.2943],[25.18066,60.34122],[25.17517,60.45248],[25.06943,60.44096],[24.9884,60.35073],[24.90051,60.38197],[25.00625,60.54175],[24.76387,60.60079],[24.50363,60.49038],[24.55307,60.36703],[24.26674,60.22549],[24.26948,59.8593]]],"type":"Polygon"}}, {"properties":{"name":"MML Orthophoto","id":"mml-orto","url":"https://tiles.kartat.kapsi.fi/ortokuva/{zoom}/{x}/{y}.jpg","attribution":{"required":true,"text":"© Maanmittauslaitos","url":"https://www.maanmittauslaitos.fi/en"},"type":"tms","category":"photo","min_zoom":2,"max_zoom":19,"best":true},"type":"Feature","geometry":{"coordinates":[[[27.96569,70.0988],[27.57431,70.07728],[27.10876,69.93548],[26.70913,69.97549],[26.45507,69.94207],[25.87142,69.6671],[25.94833,69.61024],[25.83023,69.55323],[25.66955,69.20794],[25.73822,69.01797],[25.60089,68.90309],[25.45806,68.91199],[25.11749,68.80699],[25.07354,68.64355],[24.88128,68.62003],[23.97491,68.84568],[23.74969,68.8308],[23.63433,68.71645],[23.18939,68.68053],[22.52197,68.7553],[21.63894,69.28191],[21.26953,69.31783],[20.94131,69.21622],[21.08963,69.09307],[21.05941,69.04352],[20.72296,69.12491],[20.54443,69.0558],[20.84655,68.97416],[20.81634,68.91742],[21.38754,68.68461],[22.04734,68.47066],[22.80212,68.35464],[23.12072,68.13169],[23.5437,67.9633],[23.44757,67.8393],[23.48602,67.59352],[23.36517,67.46545],[23.71124,67.41592],[23.72772,67.32186],[23.54644,67.26885],[23.53128,67.16724],[23.89251,66.86863],[23.84582,66.57775],[23.61843,66.44562],[23.67171,66.20303],[23.87191,66.14551],[24.09988,65.87247],[24.1658,65.66959],[24.11636,65.39143],[21.37939,63.68037],[20.17639,63.29787],[19.08325,60.16064],[20.22033,59.44786],[22.29125,59.44507],[25.82336,59.933],[27.52075,60.23435],[27.83386,60.53229],[29.29641,61.26165],[31.20803,62.44759],[31.62826,62.90585],[31.2635,63.22106],[29.99605,63.75387],[30.28656,63.81704],[30.58319,64.0782],[30.5104,64.26428],[30.09979,64.39218],[30.02563,64.58736],[30.16845,64.63329],[30.09429,64.79518],[29.78393,64.79811],[29.65347,64.89733],[29.65759,65.05939],[29.91027,65.09527],[29.93225,65.20895],[29.72076,65.27853],[29.91577,65.63788],[30.1863,65.66223],[29.9913,66.09771],[29.07119,66.91983],[30.11077,67.63431],[29.3486,68.08099],[28.67568,68.20166],[28.46547,68.54039],[28.72375,68.72642],[28.82675,68.87341],[28.44985,68.90792],[28.95996,69.05089],[28.83324,69.10563],[28.87207,69.22132],[29.36096,69.46526],[29.15634,69.69667],[28.38455,69.83488],[28.35845,69.88312],[28.17169,69.92511],[28.00415,70.01495],[27.96569,70.0988]]],"type":"Polygon"}}, {"properties":{"name":"MML Background Map","id":"mml-tausta","url":"https://tiles.kartat.kapsi.fi/taustakartta/{zoom}/{x}/{y}.jpg","attribution":{"required":true,"text":"© Maanmittauslaitos","url":"https://www.maanmittauslaitos.fi/en"},"type":"tms","category":"map","min_zoom":2,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[27.96569,70.0988],[27.57431,70.07728],[27.10876,69.93548],[26.70913,69.97549],[26.45507,69.94207],[25.87142,69.6671],[25.94833,69.61024],[25.83023,69.55323],[25.66955,69.20794],[25.73822,69.01797],[25.60089,68.90309],[25.45806,68.91199],[25.11749,68.80699],[25.07354,68.64355],[24.88128,68.62003],[23.97491,68.84568],[23.74969,68.8308],[23.63433,68.71645],[23.18939,68.68053],[22.52197,68.7553],[21.63894,69.28191],[21.26953,69.31783],[20.94131,69.21622],[21.08963,69.09307],[21.05941,69.04352],[20.72296,69.12491],[20.54443,69.0558],[20.84655,68.97416],[20.81634,68.91742],[21.38754,68.68461],[22.04734,68.47066],[22.80212,68.35464],[23.12072,68.13169],[23.5437,67.9633],[23.44757,67.8393],[23.48602,67.59352],[23.36517,67.46545],[23.71124,67.41592],[23.72772,67.32186],[23.54644,67.26885],[23.53128,67.16724],[23.89251,66.86863],[23.84582,66.57775],[23.61843,66.44562],[23.67171,66.20303],[23.87191,66.14551],[24.09988,65.87247],[24.1658,65.66959],[24.11636,65.39143],[21.37939,63.68037],[20.17639,63.29787],[19.08325,60.16064],[20.22033,59.44786],[22.29125,59.44507],[25.82336,59.933],[27.52075,60.23435],[27.83386,60.53229],[29.29641,61.26165],[31.20803,62.44759],[31.62826,62.90585],[31.2635,63.22106],[29.99605,63.75387],[30.28656,63.81704],[30.58319,64.0782],[30.5104,64.26428],[30.09979,64.39218],[30.02563,64.58736],[30.16845,64.63329],[30.09429,64.79518],[29.78393,64.79811],[29.65347,64.89733],[29.65759,65.05939],[29.91027,65.09527],[29.93225,65.20895],[29.72076,65.27853],[29.91577,65.63788],[30.1863,65.66223],[29.9913,66.09771],[29.07119,66.91983],[30.11077,67.63431],[29.3486,68.08099],[28.67568,68.20166],[28.46547,68.54039],[28.72375,68.72642],[28.82675,68.87341],[28.44985,68.90792],[28.95996,69.05089],[28.83324,69.10563],[28.87207,69.22132],[29.36096,69.46526],[29.15634,69.69667],[28.38455,69.83488],[28.35845,69.88312],[28.17169,69.92511],[28.00415,70.01495],[27.96569,70.0988]]],"type":"Polygon"}}, @@ -241,9 +245,9 @@ {"properties":{"name":"Hautes-Alpes 2010","id":"fr.dpt.05.2010","url":"https://wms.openstreetmap.fr/tms/1.0.0/paca05_2010/{zoom}/{x}/{y}","attribution":{"required":true,"text":"ORTHO 2010 © PACA-04-05-84","url":"http://www.crige-paca.org/geoportail/geocatalogue.html?id_lot_donnee_carto=206"},"type":"tms","category":"historicphoto","min_zoom":2,"max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[6.22101,45.13071],[6.18393,45.0119],[6.2368,44.98374],[6.31027,44.98423],[6.3089,44.93856],[6.34735,44.9371],[6.34186,44.85733],[6.30478,44.88458],[6.28143,44.88653],[6.23955,44.86852],[6.11526,44.87242],[6.0569,44.83347],[6.03699,44.84759],[6.01364,44.84857],[5.93605,44.81448],[5.93399,44.79499],[5.94566,44.79548],[5.94292,44.76916],[5.89348,44.77111],[5.89142,44.76087],[5.81863,44.76331],[5.78979,44.71747],[5.78842,44.69843],[5.80147,44.69892],[5.80147,44.68428],[5.78705,44.68281],[5.78705,44.66426],[5.73761,44.66572],[5.71289,44.64961],[5.70053,44.65693],[5.63599,44.6584],[5.63461,44.62566],[5.59547,44.57873],[5.59273,44.53372],[5.60646,44.52344],[5.62843,44.52344],[5.62843,44.5063],[5.61745,44.50679],[5.61539,44.47985],[5.56389,44.48083],[5.54123,44.49944],[5.47806,44.50091],[5.47806,44.50924],[5.45334,44.50973],[5.44853,44.43819],[5.41351,44.43819],[5.41077,44.4019],[5.42175,44.40141],[5.42107,44.35822],[5.45883,44.35724],[5.45814,44.33711],[5.48355,44.33711],[5.48218,44.32827],[5.50896,44.32729],[5.50964,44.33711],[5.53368,44.33711],[5.5323,44.31844],[5.59479,44.31648],[5.59479,44.29879],[5.62157,44.29781],[5.61882,44.27274],[5.64491,44.25159],[5.66688,44.25159],[5.66482,44.19993],[5.64217,44.19944],[5.63942,44.17974],[5.62706,44.18122],[5.62569,44.17285],[5.93948,44.16349],[5.94704,44.34497],[6.01089,44.34349],[6.01364,44.38669],[6.20109,44.38178],[6.19904,44.3376],[6.26221,44.33809],[6.26633,44.38031],[6.32812,44.37884],[6.3295,44.42397],[6.70647,44.41171],[6.71196,44.50091],[6.77513,44.49847],[6.77856,44.544],[6.84311,44.54155],[6.84654,44.58509],[6.90697,44.58411],[6.91246,44.63006],[6.9873,44.62811],[6.98524,44.63837],[6.95915,44.63983],[6.9619,44.65302],[6.97563,44.654],[6.97632,44.67207],[6.98936,44.67158],[6.99074,44.68135],[7.0388,44.6794],[7.03812,44.66914],[7.09167,44.66768],[7.09167,44.69599],[7.07725,44.69599],[7.08069,44.72234],[7.04292,44.7243],[7.0443,44.74283],[7.03125,44.74186],[7.03468,44.77842],[7.01958,44.7794],[7.02988,44.8325],[7.00928,44.83299],[7.01408,44.85198],[6.96258,44.8549],[6.9619,44.86317],[6.93855,44.86366],[6.93855,44.87242],[6.92757,44.87242],[6.90079,44.85636],[6.86165,44.85782],[6.86371,44.8656],[6.83899,44.86658],[6.84036,44.87631],[6.81427,44.8768],[6.81496,44.89528],[6.79024,44.89528],[6.79092,44.9055],[6.76346,44.90501],[6.76758,44.94925],[6.77925,44.94974],[6.782,44.96771],[6.75659,44.98811],[6.75934,45.02258],[6.68518,45.02647],[6.68655,45.05412],[6.67282,45.05364],[6.67625,45.07934],[6.6378,45.10891],[6.63917,45.12635],[6.56296,45.12974],[6.53686,45.11133],[6.49773,45.11327],[6.49773,45.10261],[6.47095,45.10212],[6.4682,45.06722],[6.37962,45.07061],[6.38374,45.10697],[6.35834,45.12587],[6.31851,45.12684],[6.31988,45.11812],[6.28212,45.11908],[6.28281,45.12877],[6.22101,45.13071]]],"type":"Polygon"}}, {"properties":{"name":"Loire-Atlantique - Orthophotos 2016 - 10 cm","id":"Loire_Atlantique-Orthophotos-2016","url":"https://wms-vuduciel2.makina-corpus.net/geoserver/wms?LAYERS=cg44:ortho44-2016&STYLES=&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":true,"text":"© Loire-Atlantique ouverture des données publiques","url":"http://data2.loire-atlantique.fr/licences/"},"type":"wms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-1.48638,46.87691],[-1.48622,46.89724],[-1.51142,46.91371],[-1.50222,46.92973],[-1.50507,46.94439],[-1.52961,46.97252],[-1.52764,47.00541],[-1.49213,47.02722],[-1.48644,46.99943],[-1.49235,46.98433],[-1.48775,46.93063],[-1.47504,46.9176],[-1.45014,46.91186],[-1.3491,46.94446],[-1.33918,46.969],[-1.34972,47.02397],[-1.28524,47.02185],[-1.26727,47.06325],[-1.21582,47.02904],[-1.14453,47.01636],[-1.09989,47.03199],[-1.09431,47.0717],[-1.14081,47.08056],[-1.15568,47.10504],[-1.20838,47.10968],[-1.20652,47.12402],[-1.1563,47.15818],[-1.14143,47.1763],[-1.16498,47.24957],[-1.20032,47.26935],[-1.23379,47.26093],[-1.28339,47.32736],[-0.97157,47.35845],[-0.92694,47.37482],[-0.9009,47.39874],[-0.93376,47.43859],[-0.93686,47.47715],[-0.94863,47.50103],[-1.0317,47.51778],[-1.13275,47.5161],[-1.13585,47.55628],[-1.0317,47.55001],[-0.98459,47.58598],[-0.99265,47.6027],[-1.09121,47.6332],[-1.13151,47.63654],[-1.15196,47.69332],[-1.18668,47.73462],[-1.21086,47.7317],[-1.22635,47.73628],[-1.21643,47.75838],[-1.23007,47.78587],[-1.346,47.81086],[-1.38133,47.84415],[-1.49911,47.84166],[-1.49601,47.81752],[-1.63735,47.77463],[-1.67455,47.72544],[-1.83077,47.72419],[-1.98016,47.70751],[-2.08121,47.66578],[-2.10055,47.65141],[-2.11141,47.62873],[-2.09981,47.62005],[-2.1001,47.61123],[-2.11783,47.60126],[-2.12109,47.54674],[-2.23223,47.51499],[-2.24836,47.52384],[-2.31063,47.53021],[-2.50573,47.50812],[-2.63913,47.41678],[-2.54862,47.28575],[-2.41658,47.25336],[-2.29694,47.22769],[-2.19341,47.25546],[-2.19217,47.16914],[-2.22627,47.17124],[-2.2678,47.12656],[-2.07067,47.08521],[-1.95475,46.98084],[-1.89276,46.94234],[-1.73468,46.87246],[-1.54437,46.84873],[-1.48638,46.87691]]],"type":"Polygon"}}, {"properties":{"name":"Lyon Orthophoto 2018 (8cm)","id":"orthophoto_lyon_2018","url":"https://imagerie.data.grandlyon.com/geoserver/grandlyon/ows?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=ortho_2018&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"Métropole de Lyon","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2018-de-la-metropole-de-lyon--format-ecw/info"},"type":"wms","category":"historicphoto","min_zoom":10,"max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[4.67728,45.9607],[4.66438,45.54676],[4.88308,45.54291],[4.8848,45.59698],[5.16666,45.59194],[5.17284,45.74596],[5.10796,45.74692],[5.11311,45.8814],[4.90677,45.88499],[4.90849,45.9213],[4.84394,45.92202],[4.84531,45.95831],[4.67728,45.9607]]],"type":"Polygon"}}, -{"properties":{"name":"Lyon Orthophoto 2012-03 10cm","id":"orthophoto_lyon_2012","url":"https://imagerie.data.grandlyon.com/geoserver/grandlyon/ows?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=ortho_2012&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"Grand Lyon Smart Data DSIT 2012","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2012-metropole-lyon/info"},"type":"wms","category":"historicphoto"},"type":"Feature","geometry":{"coordinates":[[[4.69049,45.54652],[4.83131,45.54652],[4.83131,45.57131],[4.88344,45.57131],[4.88344,45.59745],[5.16622,45.59745],[5.16622,45.74533],[5.10793,45.74533],[5.10793,45.88145],[4.90698,45.88145],[4.90698,45.92107],[4.84377,45.92107],[4.84377,45.94011],[4.71543,45.94011],[4.71543,45.87018],[4.67458,45.87018],[4.67458,45.7178],[4.69567,45.7178],[4.69049,45.54652]]],"type":"Polygon"}}, -{"properties":{"name":"Lyon Orthophoto 2015 (8cm)","id":"orthophoto_lyon","url":"https://wms.openstreetmap.fr/tms/1.0.0/lyon/{zoom}/{x}/{y}","attribution":{"required":true,"text":"Métropole de Lyon DINSI 2015","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2015-metropole-lyon-format-ecw/info"},"type":"tms","category":"historicphoto","min_zoom":2,"max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[4.66489,45.54688],[4.88253,45.54348],[4.88435,45.59745],[5.16623,45.59242],[5.17217,45.74532],[5.10793,45.74653],[5.11305,45.88145],[4.90698,45.88508],[4.90822,45.92106],[4.84377,45.92212],[4.84497,45.9581],[4.67729,45.96069],[4.66489,45.54688]]],"type":"Polygon"}}, -{"properties":{"name":"Lyon Orthophoto 2022 (5cm)","id":"orthophoto_lyon_2022","url":"https://imagerie.data.grandlyon.com/geoserver/grandlyon/ows?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=ortho_2022&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"CRAIG - Métropole du Grand Lyon 2022","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2022-de-la-metropole-de-lyon/info"},"type":"wms","category":"photo","min_zoom":10,"max_zoom":22,"best":true},"type":"Feature","geometry":{"coordinates":[[[4.74178,45.95976],[4.67728,45.9607],[4.66542,45.5649],[4.69906,45.56443],[4.69932,45.56776],[4.72876,45.56737],[4.72876,45.56617],[4.73301,45.56611],[4.73305,45.56419],[4.75507,45.56347],[4.75593,45.55451],[4.7867,45.55403],[4.787,45.55719],[4.79331,45.55713],[4.79356,45.56299],[4.80622,45.56293],[4.80687,45.58071],[4.84536,45.58011],[4.84498,45.57119],[4.87064,45.57083],[4.87128,45.58864],[4.88403,45.58969],[4.88441,45.5975],[4.90986,45.59753],[4.91038,45.60612],[5.0096,45.60444],[5.00986,45.6132],[5.0514,45.61278],[5.05226,45.63043],[5.03938,45.63073],[5.03981,45.63967],[5.05251,45.63961],[5.05312,45.64855],[5.06316,45.64825],[5.0665,45.66631],[5.07989,45.66601],[5.11972,45.69467],[5.1574,45.6933],[5.15839,45.7235],[5.15191,45.72365],[5.15199,45.72764],[5.14577,45.72782],[5.14607,45.73683],[5.13328,45.73707],[5.13341,45.7419],[5.11916,45.74226],[5.11912,45.74399],[5.10551,45.74417],[5.10607,45.75555],[5.09539,45.75579],[5.09766,45.81663],[5.03337,45.81783],[5.0332,45.81089],[4.93025,45.81269],[4.93091,45.84803],[4.92546,45.84813],[4.9255,45.84878],[4.91862,45.84888],[4.919,45.86082],[4.91639,45.86088],[4.91698,45.87592],[4.90668,45.87609],[4.90688,45.88267],[4.89953,45.88286],[4.8996,45.88453],[4.89606,45.8846],[4.89608,45.88528],[4.8941,45.8853],[4.89426,45.89024],[4.89139,45.89032],[4.89168,45.90271],[4.88519,45.90283],[4.88519,45.90345],[4.88182,45.9035],[4.8818,45.90825],[4.8753,45.90837],[4.87535,45.91027],[4.8696,45.91042],[4.86964,45.91199],[4.86527,45.91209],[4.8653,45.91278],[4.85636,45.91292],[4.85651,45.91771],[4.8395,45.91814],[4.8395,45.92219],[4.79221,45.92295],[4.7928,45.94094],[4.74122,45.94174],[4.74178,45.95976]]],"type":"Polygon"}}, +{"properties":{"name":"Lyon Orthophoto 2012 (10cm)","id":"orthophoto_lyon_2012","url":"https://imagerie.data.grandlyon.com/geoserver/grandlyon/ows?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=ortho_2012&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"Grand Lyon Smart Data DSIT 2012","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2012-metropole-lyon/info"},"type":"wms","category":"historicphoto"},"type":"Feature","geometry":{"coordinates":[[[4.69049,45.54652],[4.83131,45.54652],[4.83131,45.57131],[4.88344,45.57131],[4.88344,45.59745],[5.16622,45.59745],[5.16622,45.74533],[5.10793,45.74533],[5.10793,45.88145],[4.90698,45.88145],[4.90698,45.92107],[4.84377,45.92107],[4.84377,45.94011],[4.71543,45.94011],[4.71543,45.87018],[4.67458,45.87018],[4.67458,45.7178],[4.69567,45.7178],[4.69049,45.54652]]],"type":"Polygon"}}, +{"properties":{"name":"Lyon Orthophoto 2015 (8cm)","id":"orthophoto_lyon_2015","url":"https://wms.openstreetmap.fr/tms/1.0.0/lyon/{zoom}/{x}/{y}","attribution":{"required":true,"text":"Métropole de Lyon DINSI 2015","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2015-metropole-lyon-format-ecw/info"},"type":"tms","category":"historicphoto","min_zoom":2,"max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[4.66489,45.54688],[4.88253,45.54348],[4.88435,45.59745],[5.16623,45.59242],[5.17217,45.74532],[5.10793,45.74653],[5.11305,45.88145],[4.90698,45.88508],[4.90822,45.92106],[4.84377,45.92212],[4.84497,45.9581],[4.67729,45.96069],[4.66489,45.54688]]],"type":"Polygon"}}, +{"properties":{"name":"Lyon Orthophoto 2022 (5cm)","id":"orthophoto_lyon_2022","url":"https://imagerie.data.grandlyon.com/geoserver/grandlyon/ows?FORMAT=image/png&TRANSPARENT=TRUE&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=ortho_2022&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":true,"text":"CRAIG - Métropole du Grand Lyon 2022","url":"https://data.grandlyon.com/portail/fr/jeux-de-donnees/orthophotographie-2022-de-la-metropole-de-lyon--format-ecw/info"},"type":"wms","category":"photo","min_zoom":10,"max_zoom":22,"best":true},"type":"Feature","geometry":{"coordinates":[[[4.74178,45.95976],[4.67728,45.9607],[4.66542,45.5649],[4.69906,45.56443],[4.69932,45.56776],[4.72876,45.56737],[4.72876,45.56617],[4.73301,45.56611],[4.73305,45.56419],[4.75507,45.56347],[4.75593,45.55451],[4.7867,45.55403],[4.787,45.55719],[4.79331,45.55713],[4.79356,45.56299],[4.80622,45.56293],[4.80687,45.58071],[4.84536,45.58011],[4.84498,45.57119],[4.87064,45.57083],[4.87128,45.58864],[4.88403,45.58969],[4.88441,45.5975],[4.90986,45.59753],[4.91038,45.60612],[5.0096,45.60444],[5.00986,45.6132],[5.0514,45.61278],[5.05226,45.63043],[5.03938,45.63073],[5.03981,45.63967],[5.05251,45.63961],[5.05312,45.64855],[5.06316,45.64825],[5.0665,45.66631],[5.07989,45.66601],[5.11972,45.69467],[5.1574,45.6933],[5.15839,45.7235],[5.15191,45.72365],[5.15199,45.72764],[5.14577,45.72782],[5.14607,45.73683],[5.13328,45.73707],[5.13341,45.7419],[5.11916,45.74226],[5.11912,45.74399],[5.10551,45.74417],[5.10607,45.75555],[5.09539,45.75579],[5.09766,45.81663],[5.03337,45.81783],[5.0332,45.81089],[4.93025,45.81269],[4.93091,45.84803],[4.92546,45.84813],[4.9255,45.84878],[4.91862,45.84888],[4.919,45.86082],[4.91639,45.86088],[4.91698,45.87592],[4.90668,45.87609],[4.90688,45.88267],[4.89953,45.88286],[4.8996,45.88453],[4.89606,45.8846],[4.89608,45.88528],[4.8941,45.8853],[4.89426,45.89024],[4.89139,45.89032],[4.89168,45.90271],[4.88519,45.90283],[4.88519,45.90345],[4.88182,45.9035],[4.8818,45.90825],[4.8753,45.90837],[4.87535,45.91027],[4.8696,45.91042],[4.86964,45.91199],[4.86527,45.91209],[4.8653,45.91278],[4.85636,45.91292],[4.85651,45.91771],[4.8395,45.91814],[4.8395,45.92219],[4.79221,45.92295],[4.7928,45.94094],[4.74122,45.94174],[4.74178,45.95976]]],"type":"Polygon"}}, {"properties":{"name":"Mulhouse - 2018","id":"Mulhouse_2018","url":"https://wms.openstreetmap.fr/tms/1.0.0/mulhouse_2018/{zoom}/{x}/{y}","attribution":{"required":true,"text":"Mulhouse Alsace Agglomération 2018","url":"https://data.mulhouse-alsace.fr/explore/dataset/m2a_orthophotographie-2018/information/"},"type":"tms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[7.53731,47.78041],[7.57439,47.84128],[7.57301,47.85602],[7.55035,47.86201],[7.53525,47.84588],[7.5016,47.85141],[7.45972,47.84174],[7.4556,47.83252],[7.4453,47.83114],[7.43088,47.84128],[7.41549,47.83831],[7.39174,47.84727],[7.38007,47.83851],[7.33475,47.83989],[7.34024,47.89563],[7.31758,47.91082],[7.28737,47.89977],[7.28462,47.88412],[7.24686,47.88228],[7.23724,47.87629],[7.23312,47.86431],[7.2139,47.86524],[7.183,47.85786],[7.17613,47.84819],[7.21115,47.82284],[7.18986,47.81085],[7.19948,47.78179],[7.16789,47.77025],[7.183,47.73517],[7.17682,47.72362],[7.19467,47.69451],[7.21802,47.68527],[7.24548,47.68527],[7.25166,47.69497],[7.2448,47.70376],[7.2551,47.71392],[7.27844,47.713],[7.27982,47.70237],[7.26814,47.69405],[7.26883,47.68434],[7.28531,47.67094],[7.30247,47.66308],[7.32376,47.65984],[7.33337,47.66724],[7.3732,47.65383],[7.39242,47.65475],[7.40822,47.6603],[7.39723,47.67648],[7.42744,47.68666],[7.47551,47.69821],[7.5222,47.69636],[7.55104,47.71531],[7.56134,47.73517],[7.53731,47.78041]]],"type":"Polygon"}}, {"properties":{"name":"Nancy - Orthophoto - 2016","id":"GrandNancy_Orthophotographie_2016","url":"https://wms.openstreetmap.fr/tms/1.0.0/nancy_2016/{zoom}/{x}/{y}","attribution":{"required":true,"text":"GrandNancy Orthophotographie 2016","url":"https://wiki.openstreetmap.org/wiki/Nancy/Orthophotographie"},"type":"tms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[6.0672,48.70184],[6.06377,48.65106],[6.15097,48.59977],[6.22101,48.59886],[6.24435,48.61566],[6.29723,48.61975],[6.30478,48.73536],[6.15028,48.7503],[6.0672,48.70184]]],"type":"Polygon"}}, {"properties":{"name":"Nancy - Orthophoto","id":"GrandNancy_Orthophotographie","url":"https://wms.openstreetmap.fr/tms/1.0.0/nancy/{zoom}/{x}/{y}","attribution":{"required":true,"text":"GrandNancy Orthophotographie 2016","url":"https://wiki.openstreetmap.org/wiki/Nancy/Orthophotographie"},"type":"tms","category":"photo","max_zoom":22,"best":true},"type":"Feature","geometry":{"coordinates":[[[6.0672,48.70184],[6.06377,48.65106],[6.15097,48.59977],[6.22101,48.59886],[6.24435,48.61566],[6.29723,48.61975],[6.30478,48.73536],[6.15028,48.7503],[6.0672,48.70184]]],"type":"Polygon"}}, @@ -517,7 +521,8 @@ {"properties":{"name":"Broward County Orthoimagery (2022)","id":"Broward_Ortho_2022","url":"https://gisweb-adapters.bcpa.net/arcgis/rest/services/BCPA_WEB_BASE_22/MapServer/export?f=image&format=jpg&layers=show,3&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Broward County Property Appraiser’s Office","url":"https://gisweb-adapters.bcpa.net/bcpawebmap_ex/bcpawebmap.aspx"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-80.10267,25.97516],[-80.07117,26.33617],[-80.21877,26.33457],[-80.21867,26.34904],[-80.2674,26.34916],[-80.26732,26.36364],[-80.29687,26.36379],[-80.29766,26.18933],[-80.32984,26.18945],[-80.32993,26.17499],[-80.34598,26.17504],[-80.34602,26.16035],[-80.36222,26.16041],[-80.36224,26.14592],[-80.42654,26.14587],[-80.42648,26.16039],[-80.4589,26.1605],[-80.45599,25.95687],[-80.2948,25.95681],[-80.29473,25.97032],[-80.10267,25.97516]]],"type":"Polygon"}}, {"properties":{"name":"Broward County Orthoimagery (2023)","id":"Broward_Ortho_2023","url":"https://gisweb-adapters.bcpa.net/arcgis/rest/services/BCPA_WEB_BASE_23/MapServer/export?f=image&format=jpg&layers=show,3&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Broward County Property Appraiser’s Office","url":"https://gisweb-adapters.bcpa.net/bcpawebmap_ex/bcpawebmap.aspx"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-80.10267,25.97516],[-80.07117,26.33617],[-80.21877,26.33457],[-80.21867,26.34904],[-80.2674,26.34916],[-80.26732,26.36364],[-80.29687,26.36379],[-80.29766,26.18933],[-80.32984,26.18945],[-80.32993,26.17499],[-80.34598,26.17504],[-80.34602,26.16035],[-80.36222,26.16041],[-80.36224,26.14592],[-80.42654,26.14587],[-80.42648,26.16039],[-80.4589,26.1605],[-80.45599,25.95687],[-80.2948,25.95681],[-80.29473,25.97032],[-80.10267,25.97516]]],"type":"Polygon"}}, {"properties":{"name":"Charlotte County Orthoimagery (2020)","id":"Charlotte_Ortho_2020","url":"https://agis.charlottecountyfl.gov/arcgis/rest/services/Aerials/Raster2020/MapServer/export?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Charlotte County Geographic Information Systems","url":"https://www.charlottecountyfl.gov/gis/"},"type":"wms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-82.26451,26.94701],[-82.38809,26.94605],[-82.26226,26.71081],[-82.06476,26.7683],[-81.55921,26.76777],[-81.55814,27.04285],[-82.2647,27.0433],[-82.26451,26.94701]]],"type":"Polygon"}}, -{"properties":{"name":"Charlotte County Orthoimagery (2022)","id":"Charlotte_Ortho_2022","url":"https://agis.charlottecountyfl.gov/arcgis/rest/services/Aerials/Aerials2022_Post_IAN/MapServer/export?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Charlotte County Geographic Information Systems","url":"https://www.charlottecountyfl.gov/gis/"},"type":"wms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-82.26451,26.94701],[-82.38809,26.94605],[-82.26123,26.69942],[-82.06476,26.7683],[-82.00362,26.76846],[-82.00362,26.79597],[-81.98823,26.79592],[-81.98828,26.82343],[-81.97289,26.82343],[-81.97286,26.83721],[-81.95752,26.83719],[-81.95746,26.87845],[-81.94222,26.87854],[-81.94215,26.98851],[-81.98825,26.98844],[-81.98817,27.04348],[-82.2647,27.0433],[-82.26451,26.94701]]],"type":"Polygon"}}, +{"properties":{"name":"Charlotte County Orthoimagery (2022)","id":"Charlotte_Ortho_2022","url":"https://agis.charlottecountyfl.gov/arcgis/rest/services/Aerials/Aerials2022_Post_IAN/MapServer/export?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Charlotte County Geographic Information Systems","url":"https://www.charlottecountyfl.gov/gis/"},"type":"wms","category":"historicphoto","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-82.26451,26.94701],[-82.38809,26.94605],[-82.26123,26.69942],[-82.06476,26.7683],[-82.00362,26.76846],[-82.00362,26.79597],[-81.98823,26.79592],[-81.98828,26.82343],[-81.97289,26.82343],[-81.97286,26.83721],[-81.95752,26.83719],[-81.95746,26.87845],[-81.94222,26.87854],[-81.94215,26.98851],[-81.98825,26.98844],[-81.98817,27.04348],[-82.2647,27.0433],[-82.26451,26.94701]]],"type":"Polygon"}}, +{"properties":{"name":"Charlotte County Orthoimagery (2023)","id":"Charlotte_Ortho_2023","url":"https://agis.charlottecountyfl.gov/arcgis/rest/services/Aerials/Aerials2023/MapServer/export?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Charlotte County Geographic Information Systems","url":"https://www.charlottecountyfl.gov/gis/"},"type":"wms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-82.26451,26.94701],[-82.38809,26.94605],[-82.26123,26.69942],[-82.06476,26.7683],[-82.00362,26.76846],[-82.00362,26.79597],[-81.98823,26.79592],[-81.98828,26.82343],[-81.97289,26.82343],[-81.97286,26.83721],[-81.95752,26.83719],[-81.95746,26.87845],[-81.94222,26.87854],[-81.94215,26.98851],[-81.98825,26.98844],[-81.98817,27.04348],[-82.2647,27.0433],[-82.26451,26.94701]]],"type":"Polygon"}}, {"properties":{"name":"Citrus County Orthoimagery (2020)","id":"Citrus_Ortho_2020","url":"https://gis.citruspa.org/arcgisweb/rest/services/Tyler/2020_Aerials/MapServer/export?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Citrus County Property Appraiser's Office","url":"https://www.citruspa.org/"},"type":"wms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-82.78572,29.0214],[-82.7192,28.69176],[-82.42429,28.69321],[-82.42452,28.65186],[-82.25311,28.65241],[-82.25289,28.67976],[-82.23799,28.67987],[-82.23733,28.72122],[-82.22215,28.72122],[-82.22193,28.73484],[-82.20637,28.73517],[-82.20626,28.74873],[-82.17513,28.74873],[-82.17524,28.77641],[-82.15979,28.77652],[-82.15985,28.81754],[-82.1753,28.81748],[-82.17538,28.83132],[-82.19108,28.83135],[-82.19097,28.84508],[-82.2067,28.84502],[-82.20667,28.85881],[-82.22229,28.85883],[-82.22238,28.87248],[-82.23755,28.8724],[-82.23805,28.90013],[-82.26901,28.89957],[-82.26923,28.92714],[-82.28468,28.92659],[-82.28512,28.95449],[-82.30046,28.9546],[-82.30069,28.98216],[-82.31625,28.98205],[-82.31614,28.99595],[-82.34748,28.99595],[-82.34793,29.00973],[-82.37883,29.00929],[-82.37905,29.02329],[-82.3945,29.0234],[-82.39461,29.03697],[-82.42618,29.03708],[-82.42602,29.05086],[-82.45742,29.05058],[-82.45764,29.06487],[-82.50444,29.06442],[-82.50444,29.05053],[-82.58281,29.05008],[-82.58236,29.03624],[-82.73893,29.03574],[-82.7387,29.02196],[-82.78572,29.0214]]],"type":"Polygon"}}, {"properties":{"name":"Collier County Orthoimagery (2022)","id":"Collier_Ortho_2022","url":"https://ags2.colliercountyfl.gov/imagery/rest/services/Orthos2022/ImageServer/exportImage?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Collier County Information Technology GIS Team","url":"https://hub-collierbcc.opendata.arcgis.com/"},"type":"wms","category":"historicphoto","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-80.85707,26.31698],[-81.22402,26.31665],[-81.22445,26.53704],[-81.59119,26.536],[-81.59079,26.48124],[-81.71292,26.48063],[-81.71234,26.42575],[-81.89595,26.42477],[-81.76936,25.76545],[-80.85773,25.76874],[-80.85707,26.31698]]],"type":"Polygon"}}, {"properties":{"name":"Collier County Orthoimagery (Latest)","id":"Collier_Ortho_Latest","url":"https://ags2.colliercountyfl.gov/imagery/rest/services/CurrentOrthos/ImageServer/exportImage?f=image&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Collier County Information Technology GIS Team","url":"https://hub-collierbcc.opendata.arcgis.com/"},"type":"wms","category":"photo","max_zoom":22},"type":"Feature","geometry":{"coordinates":[[[-80.85707,26.31698],[-81.22402,26.31665],[-81.22445,26.53704],[-81.59119,26.536],[-81.59079,26.48124],[-81.71292,26.48063],[-81.71234,26.42575],[-81.89595,26.42477],[-81.76936,25.76545],[-80.85773,25.76874],[-80.85707,26.31698]]],"type":"Polygon"}}, @@ -550,17 +555,19 @@ {"properties":{"name":"City of Naples Orthoimagery (2020)","id":"Naples_FL_Ortho_2020","url":"https://g.naplesgov.com/arcgis/rest/services/Imagery/NAPLES_2020/ImageServer/exportImage?f=image&format=jpg&imageSR={wkid}&bboxSR={wkid}&bbox={bbox}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Collier County Property Appraiser’s Office, Naples GIS","url":"https://g.naplesgov.com/cityofnaplesgis2/"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-81.89578,26.42447],[-81.52919,26.42631],[-81.5285,26.27909],[-81.51477,26.27918],[-81.51437,26.19255],[-81.52803,26.19245],[-81.5262,25.82107],[-81.83073,25.81984],[-81.83226,26.09502],[-81.8928,26.09488],[-81.89578,26.42447]]],"type":"Polygon"}}, {"properties":{"name":"Okaloosa County Orthoimagery (2019)","id":"Okaloosa_Ortho_2019","url":"https://ags.myokaloosa.com/arcgis/rest/services/imagery/Aerial2019/MapServer/WMTS/tile/1.0.0/imagery_Aerial2019/default/default028mm/{zoom}/{y}/{x}.jpg","attribution":{"required":false,"text":"Okaloosa County, FL GIS","url":"https://myokaloosa.com/gis_homepage"},"type":"tms","category":"historicphoto","max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[-86.79553,31.00315],[-86.79162,30.83611],[-86.80524,30.8358],[-86.80032,30.48768],[-86.8087,30.48752],[-86.80721,30.42335],[-86.81146,30.42328],[-86.81073,30.38239],[-86.38213,30.37511],[-86.37831,31.00762],[-86.79553,31.00315]]],"type":"Polygon"}}, {"properties":{"name":"Okaloosa County Orthoimagery (2022)","id":"Okaloosa_Ortho_2022","url":"https://ags.myokaloosa.com/arcgis/rest/services/imagery/Aerial2022_dynamic/MapServer/export?dpi=96&transparent=true&format=jpg&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&f=image&foo={proj}","attribution":{"required":false,"text":"Okaloosa County, FL GIS","url":"https://myokaloosa.com/gis_homepage"},"type":"wms","category":"photo","max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[-86.79553,31.00315],[-86.79162,30.83611],[-86.80524,30.8358],[-86.80032,30.48768],[-86.8087,30.48752],[-86.80721,30.42335],[-86.81146,30.42328],[-86.81073,30.38239],[-86.38213,30.37511],[-86.37831,31.00762],[-86.79553,31.00315]]],"type":"Polygon"}}, -{"properties":{"name":"Palm-Beach County Orthoimagery (2021)","id":"Palm-Beach_Ortho_2021","url":"https://maps.co.palm-beach.fl.us/arcgis/rest/services/Aerials/2021/MapServer/export?f=image&format=jpg&layers=show,0&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Palm Beach County","url":"http://maps.co.palm-beach.fl.us/cwgis/mygeonav.html"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-80.6351,26.98808],[-80.63519,26.97425],[-80.61978,26.97425],[-80.62004,26.8917],[-80.71235,26.7819],[-80.75835,26.78199],[-80.7584,26.74074],[-80.85037,26.74085],[-80.85036,26.75462],[-80.86567,26.75464],[-80.86565,26.78213],[-80.89628,26.78218],[-80.89671,26.31446],[-80.0572,26.31134],[-80.02463,26.55876],[-80.0223,26.83382],[-80.06716,26.98546],[-80.6351,26.98808]]],"type":"Polygon"}}, -{"properties":{"name":"Palm-Beach County Orthoimagery (2022)","id":"Palm-Beach_Ortho_2022","url":"https://maps.co.palm-beach.fl.us/arcgis/rest/services/Aerials/2022/MapServer/export?f=image&format=jpg&layers=show,0&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Palm Beach County","url":"http://maps.co.palm-beach.fl.us/cwgis/mygeonav.html"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[[-80.38942,26.9872],[-80.39108,26.67082],[-80.36056,26.67048],[-80.36035,26.64297],[-80.34524,26.64297],[-80.34532,26.62938],[-80.33013,26.62931],[-80.33021,26.61555],[-80.31489,26.61542],[-80.31502,26.60174],[-80.2844,26.60156],[-80.28448,26.58782],[-80.26916,26.58776],[-80.26928,26.57398],[-80.25398,26.57394],[-80.25391,26.54662],[-80.23885,26.5462],[-80.23893,26.51881],[-80.22375,26.51874],[-80.22415,26.4637],[-80.23942,26.46376],[-80.23993,26.38124],[-80.25522,26.38129],[-80.25533,26.36757],[-80.30111,26.36783],[-80.30143,26.31279],[-80.05733,26.31191],[-80.02463,26.55876],[-80.0223,26.83382],[-80.06716,26.98546],[-80.38942,26.9872]]],[[[-80.63533,26.89178],[-80.63553,26.86419],[-80.65085,26.86423],[-80.6509,26.85056],[-80.66618,26.85058],[-80.66628,26.83679],[-80.68152,26.83679],[-80.6817,26.7956],[-80.63568,26.79553],[-80.63559,26.82308],[-80.62035,26.823],[-80.62025,26.83673],[-80.60494,26.83669],[-80.60473,26.89167],[-80.63533,26.89178]]],[[[-80.68185,26.74057],[-80.6819,26.71311],[-80.7125,26.71307],[-80.7128,26.68565],[-80.7432,26.68565],[-80.74337,26.65814],[-80.728,26.65814],[-80.728,26.64442],[-80.66681,26.64428],[-80.66672,26.65806],[-80.62082,26.65786],[-80.62069,26.69915],[-80.63604,26.69915],[-80.636,26.71295],[-80.6513,26.71299],[-80.65121,26.7405],[-80.68185,26.74057]]]],"type":"MultiPolygon"}}, +{"properties":{"name":"Palm Beach County Orthoimagery (2021)","id":"Palm-Beach_Ortho_2021","url":"https://maps.co.palm-beach.fl.us/arcgis/rest/services/Aerials/2021/MapServer/export?f=image&format=jpg&layers=show,0&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Palm Beach County","url":"http://maps.co.palm-beach.fl.us/cwgis/mygeonav.html"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-80.6351,26.98808],[-80.63519,26.97425],[-80.61978,26.97425],[-80.62004,26.8917],[-80.71235,26.7819],[-80.75835,26.78199],[-80.7584,26.74074],[-80.85037,26.74085],[-80.85036,26.75462],[-80.86567,26.75464],[-80.86565,26.78213],[-80.89628,26.78218],[-80.89671,26.31446],[-80.0572,26.31134],[-80.02463,26.55876],[-80.0223,26.83382],[-80.06716,26.98546],[-80.6351,26.98808]]],"type":"Polygon"}}, +{"properties":{"name":"Palm Beach County Orthoimagery (2022)","id":"Palm-Beach_Ortho_2022","url":"https://maps.co.palm-beach.fl.us/arcgis/rest/services/Aerials/2022/MapServer/export?f=image&format=jpg&layers=show,0&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Palm Beach County","url":"http://maps.co.palm-beach.fl.us/cwgis/mygeonav.html"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[[-80.38942,26.9872],[-80.39108,26.67082],[-80.36056,26.67048],[-80.36035,26.64297],[-80.34524,26.64297],[-80.34532,26.62938],[-80.33013,26.62931],[-80.33021,26.61555],[-80.31489,26.61542],[-80.31502,26.60174],[-80.2844,26.60156],[-80.28448,26.58782],[-80.26916,26.58776],[-80.26928,26.57398],[-80.25398,26.57394],[-80.25391,26.54662],[-80.23885,26.5462],[-80.23893,26.51881],[-80.22375,26.51874],[-80.22415,26.4637],[-80.23942,26.46376],[-80.23993,26.38124],[-80.25522,26.38129],[-80.25533,26.36757],[-80.30111,26.36783],[-80.30143,26.31279],[-80.05733,26.31191],[-80.02463,26.55876],[-80.0223,26.83382],[-80.06716,26.98546],[-80.38942,26.9872]]],[[[-80.63533,26.89178],[-80.63553,26.86419],[-80.65085,26.86423],[-80.6509,26.85056],[-80.66618,26.85058],[-80.66628,26.83679],[-80.68152,26.83679],[-80.6817,26.7956],[-80.63568,26.79553],[-80.63559,26.82308],[-80.62035,26.823],[-80.62025,26.83673],[-80.60494,26.83669],[-80.60473,26.89167],[-80.63533,26.89178]]],[[[-80.68185,26.74057],[-80.6819,26.71311],[-80.7125,26.71307],[-80.7128,26.68565],[-80.7432,26.68565],[-80.74337,26.65814],[-80.728,26.65814],[-80.728,26.64442],[-80.66681,26.64428],[-80.66672,26.65806],[-80.62082,26.65786],[-80.62069,26.69915],[-80.63604,26.69915],[-80.636,26.71295],[-80.6513,26.71299],[-80.65121,26.7405],[-80.68185,26.74057]]]],"type":"MultiPolygon"}}, +{"properties":{"name":"Palm Beach County Orthoimagery (2023)","id":"Palm-Beach_Ortho_2023","url":"https://maps.co.palm-beach.fl.us/arcgis/rest/services/Aerials/2023/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Palm Beach County","url":"http://maps.co.palm-beach.fl.us/cwgis/mygeonav.html"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[[-80.38942,26.9872],[-80.39108,26.67082],[-80.36056,26.67048],[-80.36035,26.64297],[-80.34524,26.64297],[-80.34532,26.62938],[-80.33013,26.62931],[-80.33021,26.61555],[-80.31489,26.61542],[-80.31502,26.60174],[-80.2844,26.60156],[-80.28448,26.58782],[-80.26916,26.58776],[-80.26928,26.57398],[-80.25398,26.57394],[-80.25391,26.54662],[-80.23885,26.5462],[-80.23893,26.51881],[-80.22375,26.51874],[-80.22415,26.4637],[-80.23942,26.46376],[-80.23993,26.38124],[-80.25522,26.38129],[-80.25533,26.36757],[-80.30111,26.36783],[-80.30143,26.31279],[-80.05733,26.31191],[-80.02463,26.55876],[-80.0223,26.83382],[-80.06716,26.98546],[-80.38942,26.9872]]],[[[-80.63533,26.89178],[-80.63553,26.86419],[-80.65085,26.86423],[-80.6509,26.85056],[-80.66618,26.85058],[-80.66628,26.83679],[-80.68152,26.83679],[-80.6817,26.7956],[-80.63568,26.79553],[-80.63559,26.82308],[-80.62035,26.823],[-80.62025,26.83673],[-80.60494,26.83669],[-80.60473,26.89167],[-80.63533,26.89178]]],[[[-80.68185,26.74057],[-80.6819,26.71311],[-80.7125,26.71307],[-80.7128,26.68565],[-80.7432,26.68565],[-80.74337,26.65814],[-80.728,26.65814],[-80.728,26.64442],[-80.66681,26.64428],[-80.66672,26.65806],[-80.62082,26.65786],[-80.62069,26.69915],[-80.63604,26.69915],[-80.636,26.71295],[-80.6513,26.71299],[-80.65121,26.7405],[-80.68185,26.74057]]]],"type":"MultiPolygon"}}, {"properties":{"name":"Pinellas County Orthoimagery (2023)","id":"Pinellas_Ortho_2023","url":"https://egis.pinellas.gov/gis/rest/services/Aerials/Aerials2023/ImageServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Pinellas County","url":"https://new-pinellas-egis.opendata.arcgis.com/"},"type":"tms","category":"photo","max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[-82.77539,27.56428],[-82.60568,27.57869],[-82.56087,27.86767],[-82.56115,27.93635],[-82.62383,27.96377],[-82.62299,27.97733],[-82.63902,28.00488],[-82.63998,28.18353],[-82.96373,28.18228],[-82.77539,27.56428]]],"type":"Polygon"}}, -{"properties":{"name":"Saint Johns County Natural Color Orthoimagery (2021)","id":"Saint_Johns_Ortho_2021","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Imagery_2021_color/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, -{"properties":{"name":"Saint Johns County Infrared Orthoimagery (2021)","id":"Saint_Johns_Ortho_CIR_2021","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Imagery_2021_cir/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, +{"properties":{"name":"Saint Johns County Basemap","id":"Saint_Johns_Basemap","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Basemap/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"map","max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, +{"properties":{"name":"Saint Johns County Natural Color Orthoimagery (2021)","id":"Saint_Johns_Ortho_2021","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Imagery_2021_color/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"historicphoto","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, +{"properties":{"name":"Saint Johns County Infrared Orthoimagery (2021)","id":"Saint_Johns_Ortho_CIR_2021","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Imagery_2021_cir/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"historicphoto","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, +{"properties":{"name":"Saint Johns County Infrared Orthoimagery (2023)","id":"Saint_Johns_Ortho_CIR_2023","url":"https://www.gis.sjcfl.us/portal_sjcgis/rest/services/Imagery_2023_cir/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Johns County GIS","url":"https://www.sjcfl.us/GIS/index.aspx"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-81.60172,29.96152],[-81.55467,29.61383],[-81.31862,29.61478],[-81.31851,29.62861],[-81.30255,29.62866],[-81.30286,29.64208],[-81.25476,29.64302],[-81.25524,29.65464],[-81.20855,29.65617],[-81.3203,30.2611],[-81.44677,30.26085],[-81.44662,30.13673],[-81.50903,30.13727],[-81.50946,30.15077],[-81.58879,30.15028],[-81.58878,30.13628],[-81.65218,30.13561],[-81.68584,30.03107],[-81.60172,29.96152]]],"type":"Polygon"}}, {"properties":{"name":"Saint Lucie County Orthoimagery (2021)","id":"Saint_Lucie_Ortho_2021","url":"https://tiles.arcgis.com/tiles/UZU5YYWrSlE9YWnx/arcgis/rest/services/2021_Aerial_Imagery/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Lucie County Property Appraiser’s Office","url":"https://www.paslc.gov/"},"type":"tms","category":"historicphoto","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-80.69494,27.5659],[-80.69595,27.19453],[-80.28066,27.19288],[-80.28031,27.24802],[-80.18807,27.24748],[-80.32276,27.56457],[-80.69494,27.5659]]],"type":"Polygon"}}, {"properties":{"name":"Saint Lucie County Orthoimagery (2023)","id":"Saint_Lucie_Ortho_2023","url":"https://tiles.arcgis.com/tiles/UZU5YYWrSlE9YWnx/arcgis/rest/services/2023_Aerial_Imagery/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Saint Lucie County Property Appraiser’s Office","url":"https://www.paslc.gov/"},"type":"tms","category":"photo","max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-80.69494,27.5659],[-80.69595,27.19453],[-80.28066,27.19288],[-80.28031,27.24802],[-80.18807,27.24748],[-80.32276,27.56457],[-80.69494,27.5659]]],"type":"Polygon"}}, {"properties":{"name":"Sarasota County Orthoimagery (2023)","id":"Sarasota_Ortho_2023","url":"https://ags3.scgov.net/agsfed/rest/services/ImageServices/SC2023WM/ImageServer/WMTS/tile/1.0.0/ImageServices_SC2023WM/default/default028mm/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Sarasota County GIS","url":"https://data-sarco.opendata.arcgis.com/"},"type":"tms","category":"photo","min_zoom":8,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-82.23475,27.40096],[-82.65082,27.39964],[-82.40258,26.93293],[-82.24912,26.93328],[-82.24933,27.02957],[-82.0343,27.02979],[-82.03436,27.22235],[-82.23438,27.22216],[-82.23475,27.40096]]],"type":"Polygon"}}, {"properties":{"name":"Seminole County Orthoimagery (2021)","id":"Seminole_Ortho_2021","url":"https://maps2.scpafl.org/arcgis/rest/services/Aerials2021/MapServer/export?f=image&format=jpg&layers=show,0&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Seminole County GIS","url":"https://maps2.scpafl.org/SCPAExternal/"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-81.45946,28.72408],[-81.45972,28.63987],[-81.362,28.64017],[-81.36198,28.63692],[-81.33388,28.63696],[-81.33385,28.61057],[-80.98709,28.61293],[-80.98709,28.63693],[-81.00331,28.637],[-81.00331,28.6805],[-81.01988,28.68059],[-81.01986,28.69501],[-81.00333,28.69501],[-81.00333,28.70098],[-81.02097,28.70099],[-81.02097,28.72408],[-81.03636,28.72409],[-81.05676,28.7877],[-81.05677,28.80228],[-81.06738,28.80228],[-81.06739,28.81119],[-81.06944,28.81119],[-81.06945,28.82572],[-81.10248,28.82571],[-81.10248,28.82889],[-81.13554,28.82887],[-81.13554,28.81121],[-81.15207,28.81119],[-81.15203,28.79664],[-81.20161,28.79669],[-81.20164,28.81122],[-81.21814,28.81121],[-81.21818,28.8232],[-81.30074,28.82571],[-81.30079,28.84027],[-81.31726,28.84023],[-81.31731,28.85479],[-81.35032,28.85476],[-81.35031,28.87371],[-81.36304,28.87369],[-81.36301,28.87847],[-81.36708,28.87849],[-81.36708,28.87364],[-81.3834,28.8736],[-81.3834,28.86934],[-81.39999,28.86928],[-81.39995,28.85481],[-81.41649,28.85473],[-81.41644,28.82576],[-81.41981,28.82573],[-81.4197,28.79666],[-81.4165,28.79667],[-81.41645,28.75314],[-81.43302,28.75311],[-81.43302,28.72411],[-81.45946,28.72408]]],"type":"Polygon"}}, {"properties":{"name":"Seminole County Orthoimagery (2023)","id":"Seminole_Ortho_2023","url":"https://seminolearcgis.seminolecountyfl.gov:6443/arcgis/rest/services/Aerials2023/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Seminole County GIS","url":"https://maps2.scpafl.org/SCPAExternal/"},"type":"tms","category":"photo","max_zoom":23},"type":"Feature","geometry":{"coordinates":[[[-81.45946,28.72408],[-81.45972,28.63987],[-81.362,28.64017],[-81.36198,28.63692],[-81.33388,28.63696],[-81.33385,28.61057],[-80.98709,28.61293],[-80.98709,28.63693],[-81.00331,28.637],[-81.00331,28.6805],[-81.01988,28.68059],[-81.01986,28.69501],[-81.00333,28.69501],[-81.00333,28.70098],[-81.02097,28.70099],[-81.02097,28.72408],[-81.03636,28.72409],[-81.05676,28.7877],[-81.05677,28.80228],[-81.06738,28.80228],[-81.06739,28.81119],[-81.06944,28.81119],[-81.06945,28.82572],[-81.10248,28.82571],[-81.10248,28.82889],[-81.13554,28.82887],[-81.13554,28.81121],[-81.15207,28.81119],[-81.15203,28.79664],[-81.20161,28.79669],[-81.20164,28.81122],[-81.21814,28.81121],[-81.21818,28.8232],[-81.30074,28.82571],[-81.30079,28.84027],[-81.31726,28.84023],[-81.31731,28.85479],[-81.35032,28.85476],[-81.35031,28.87371],[-81.36304,28.87369],[-81.36301,28.87847],[-81.36708,28.87849],[-81.36708,28.87364],[-81.3834,28.8736],[-81.3834,28.86934],[-81.39999,28.86928],[-81.39995,28.85481],[-81.41649,28.85473],[-81.41644,28.82576],[-81.41981,28.82573],[-81.4197,28.79666],[-81.4165,28.79667],[-81.41645,28.75314],[-81.43302,28.75311],[-81.43302,28.72411],[-81.45946,28.72408]]],"type":"Polygon"}}, -{"properties":{"name":"Sumter County Orthoimagery (2021)","id":"Sumter_Ortho_2021","url":"https://gis.sumtercountyfl.gov/sumtergis/rest/services/Imagery/Imagery2021_EV/MapServer/export?f=image&format=jpg&layers=&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Sumter County GIS, Sumter County Board of County Commissioners","url":"https://data2-sumtercountygis.opendata.arcgis.com/"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-81.9411,28.96893],[-81.94136,28.39095],[-81.95685,28.39099],[-81.95706,28.29501],[-82.00367,28.29516],[-82.00367,28.30922],[-82.0659,28.30914],[-82.0659,28.51516],[-82.11267,28.51508],[-82.11259,28.52888],[-82.12812,28.52896],[-82.1283,28.54276],[-82.14383,28.54268],[-82.14383,28.55633],[-82.19069,28.55618],[-82.19061,28.57013],[-82.22168,28.57005],[-82.22177,28.58377],[-82.23756,28.58384],[-82.23739,28.6112],[-82.25301,28.61127],[-82.25301,28.62499],[-82.26852,28.62504],[-82.26854,28.6387],[-82.28421,28.63874],[-82.28429,28.66611],[-82.26871,28.66623],[-82.26867,28.69364],[-82.25314,28.69375],[-82.25318,28.735],[-82.23764,28.735],[-82.23764,28.7487],[-82.22198,28.7487],[-82.22207,28.76247],[-82.19078,28.76254],[-82.19091,28.8176],[-82.20659,28.81757],[-82.2067,28.83133],[-82.22215,28.83125],[-82.22232,28.84494],[-82.23799,28.84494],[-82.23799,28.85881],[-82.25348,28.85869],[-82.25352,28.87249],[-82.2691,28.87252],[-82.26919,28.88632],[-82.28472,28.88628],[-82.28481,28.91367],[-82.3006,28.91378],[-82.30052,28.94124],[-82.31622,28.94127],[-82.31627,28.96854],[-81.9411,28.96893]]],"type":"Polygon"}}, {"properties":{"name":"Volusia County Orthoimagery (2021)","id":"Volusia_Ortho_2021","url":"https://maps2.vcgov.org/arcgis/rest/services/Aerial_2021/ImageServer/exportImage?f=image&format=jpg&imageSR={wkid}&bboxSR={wkid}&bbox={bbox}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Volusia County Property Appraiser’s Office","url":"https://volusiacountyfl.maps.arcgis.com/apps/webappviewer/index.html?id=b773f4bfcadd4d9aa8b99cb599e0aec6"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-80.72269,28.78991],[-81.0979,29.43646],[-81.12929,29.43639],[-81.1293,29.42265],[-81.16071,29.42261],[-81.16048,29.27136],[-81.4114,29.27083],[-81.41196,29.40834],[-81.44324,29.40824],[-81.4432,29.39444],[-81.45899,29.39448],[-81.45899,29.3806],[-81.50601,29.38052],[-81.50598,29.36677],[-81.5687,29.36652],[-81.56868,29.3527],[-81.59975,29.35278],[-81.58344,29.18769],[-81.56774,29.18774],[-81.56761,29.17405],[-81.53628,29.17408],[-81.53615,29.14665],[-81.52053,29.14669],[-81.52023,29.10556],[-81.50456,29.10553],[-81.50456,29.09158],[-81.47306,29.09173],[-81.47315,29.06435],[-81.45736,29.0645],[-81.45736,29.05077],[-81.44174,29.05077],[-81.44165,29.03711],[-81.42612,29.03704],[-81.42594,29.02338],[-81.41032,29.02338],[-81.41024,29.00957],[-81.3947,29.00964],[-81.39462,28.9959],[-81.37882,28.99605],[-81.37882,28.95483],[-81.3632,28.95483],[-81.36303,28.89977],[-81.37874,28.89954],[-81.37839,28.85851],[-81.36312,28.85858],[-81.36286,28.84452],[-81.34724,28.84475],[-81.34707,28.83106],[-81.23789,28.83122],[-81.23776,28.8176],[-81.22222,28.81753],[-81.22201,28.79],[-81.19085,28.79008],[-81.19094,28.77631],[-81.15944,28.77631],[-81.15961,28.79],[-81.12845,28.78985],[-81.1285,28.80388],[-81.11292,28.80395],[-81.11283,28.81772],[-81.09725,28.81768],[-81.09734,28.80392],[-81.08163,28.80392],[-81.08168,28.79004],[-81.06601,28.79012],[-81.05035,28.70768],[-81.0349,28.70753],[-81.03464,28.66627],[-81.01902,28.66642],[-81.01911,28.62514],[-81.00357,28.62506],[-81.00348,28.61135],[-80.95684,28.61135],[-80.95679,28.7903],[-80.72269,28.78991]]],"type":"Polygon"}}, {"properties":{"name":"Athens-Clarke County Imagery (2018)","id":"ACC_2018","url":"https://tiles.arcgis.com/tiles/xSEULKvB31odt3XQ/arcgis/rest/services/2018_Ortho_Imagery/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":true,"text":"Athens-Clarke County GIS","url":"https://data-athensclarke.opendata.arcgis.com/"},"type":"tms","category":"historicphoto","min_zoom":8,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-83.39172,33.8727],[-83.30933,33.83506],[-83.20633,33.86243],[-83.25577,33.96386],[-83.35739,34.02193],[-83.45078,33.99689],[-83.50433,33.92627],[-83.39172,33.8727]]],"type":"Polygon"}}, {"properties":{"name":"Maui County Orthoimagery (2023)","id":"Maui_2023","url":"https://tiles.arcgis.com/tiles/fsrDo0QMPlK9CkZD/arcgis/rest/services/Pictometry2023_MauiCounty282/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"Maui County GIS","url":"https://mauicounty.maps.arcgis.com/home/index.html"},"type":"tms","category":"photo","min_zoom":2,"max_zoom":21,"best":true},"type":"Feature","geometry":{"coordinates":[[[-157.37227,21.28684],[-157.37227,20.45357],[-155.92272,20.45357],[-155.92272,21.28684],[-157.37227,21.28684]]],"type":"Polygon"}}, @@ -575,7 +582,8 @@ {"properties":{"name":"KyFromAbove Aerial Imagery (2012-2014)","id":"KYAPED_Phase_1","url":"https://kyraster.ky.gov/arcgis/services/ImageServices/Ky_KYAPED_Imagery_WGS84WM/ImageServer/WMSServer?LAYERS=0&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":false,"text":"KyFromAbove","url":"https://kyfromabove.ky.gov/"},"type":"wms","category":"historicphoto","min_zoom":3,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[[-89.55251,36.57723],[-89.55264,36.57718],[-89.57151,36.55257],[-89.54296,36.50496],[-89.53912,36.4981],[-89.4885,36.49755],[-89.4852,36.49745],[-89.46589,36.52995],[-89.46545,36.53616],[-89.4808,36.56969],[-89.48089,36.56977],[-89.5205,36.57943],[-89.52234,36.58018],[-89.55251,36.57723]]],[[[-89.36555,36.62506],[-89.37545,36.61572],[-89.37637,36.61387],[-89.41729,36.49903],[-89.34795,36.50308],[-89.30028,36.50715],[-88.06598,36.49774],[-88.05332,36.49712],[-88.0453,36.50408],[-88.03948,36.51041],[-88.03413,36.53112],[-88.03249,36.54066],[-88.0412,36.58412],[-88.04513,36.60294],[-88.06821,36.65975],[-88.07053,36.67812],[-87.85045,36.6651],[-87.85354,36.63507],[-87.69783,36.637],[-87.69385,36.63707],[-87.68285,36.70333],[-87.67503,36.7501],[-87.67186,36.8785],[-87.66,36.96624],[-87.72956,36.9999],[-87.73366,37.00209],[-87.7106,37.02156],[-87.68078,37.14928],[-87.66878,37.14975],[-87.64964,37.14692],[-87.52378,37.10601],[-87.52029,37.10516],[-87.48508,37.12661],[-87.37442,37.13381],[-87.35981,37.1499],[-87.35998,37.1567],[-87.34036,37.15745],[-87.33626,37.1548],[-87.3151,37.18731],[-87.31174,37.19144],[-87.34575,37.21178],[-87.34988,37.2149],[-87.34719,37.2231],[-87.349,37.22625],[-87.37141,37.24404],[-87.36402,37.24914],[-87.38553,37.25335],[-87.38852,37.25738],[-87.38414,37.2901],[-87.38602,37.29551],[-87.37801,37.29926],[-87.37221,37.29889],[-87.3793,37.30468],[-87.38004,37.31102],[-87.37377,37.31474],[-87.37091,37.31614],[-87.35457,37.3105],[-87.34586,37.30973],[-87.33775,37.33252],[-87.33726,37.33615],[-87.31243,37.36282],[-87.30045,37.37026],[-87.30749,37.37378],[-87.3093,37.37693],[-87.30595,37.38197],[-87.29575,37.39164],[-87.33332,37.41148],[-87.3528,37.42569],[-87.3548,37.48279],[-87.36243,37.4863],[-87.35148,37.51231],[-87.34924,37.51552],[-87.35952,37.53213],[-87.36652,37.53339],[-87.36037,37.54255],[-87.35931,37.54665],[-87.37499,37.56998],[-87.37986,37.57898],[-87.39521,37.58871],[-87.46038,37.59267],[-87.4803,37.59914],[-87.49965,37.62694],[-87.49557,37.64786],[-87.73424,37.63828],[-87.94307,37.46638],[-87.94375,37.46563],[-87.93037,37.41046],[-87.93019,37.4092],[-87.91391,37.41123],[-87.91313,37.41104],[-87.91564,37.40477],[-87.91545,37.40448],[-87.90281,37.39822],[-87.90195,37.39824],[-87.86945,37.40519],[-87.86876,37.40518],[-87.86164,37.40894],[-87.86131,37.40954],[-87.86595,37.41683],[-87.86561,37.41728],[-87.84737,37.42062],[-87.84638,37.42046],[-87.84426,37.39512],[-87.84426,37.39482],[-87.85904,37.39277],[-87.85964,37.39241],[-87.86,37.38071],[-87.86003,37.3802],[-87.84335,37.37468],[-87.84282,37.37469],[-87.81953,37.38776],[-87.81861,37.38832],[-87.81061,37.37686],[-87.81042,37.37645],[-87.80095,37.3794],[-87.80122,37.37898],[-88.05239,37.23751],[-88.05269,37.22934],[-88.07805,37.22699],[-88.08885,37.22178],[-88.08231,37.21647],[-88.08042,37.21198],[-88.08376,37.20828],[-88.08891,37.20681],[-88.08443,37.1942],[-88.08301,37.18652],[-88.09489,37.17947],[-88.10183,37.17932],[-88.10889,37.16647],[-88.1099,37.16237],[-88.13168,37.15736],[-88.13252,37.14872],[-88.14131,37.15216],[-88.14428,37.15436],[-88.16293,37.14307],[-88.16557,37.13575],[-88.1919,37.12927],[-88.1966,37.13144],[-88.18787,37.16156],[-88.19039,37.1674],[-88.21927,37.18309],[-88.21986,37.18353],[-88.20455,37.20746],[-88.20065,37.21162],[-88.20258,37.23289],[-88.20032,37.23431],[-88.21851,37.27335],[-88.29375,37.33559],[-88.29557,37.33782],[-88.30556,37.37206],[-88.29948,37.37991],[-88.31327,37.39228],[-88.31811,37.39761],[-88.36547,37.40166],[-88.37121,37.40273],[-88.40624,37.42479],[-88.40881,37.42522],[-88.46586,37.40055],[-88.47022,37.39625],[-88.48672,37.34015],[-88.48695,37.3396],[-88.51406,37.29246],[-88.51486,37.29069],[-88.50409,37.26514],[-88.50382,37.26485],[-88.5123,37.26295],[-88.51187,37.26201],[-88.45005,37.2062],[-88.44982,37.20599],[-88.42533,37.15421],[-88.42462,37.15173],[-88.44912,37.08875],[-88.44919,37.08776],[-88.45919,37.07523],[-88.46019,37.07447],[-88.48622,37.06659],[-88.48605,37.0648],[-88.56528,37.07521],[-88.56587,37.0752],[-88.62221,37.11775],[-88.62589,37.11946],[-88.68777,37.13938],[-88.69398,37.14115],[-88.73125,37.14368],[-88.73211,37.14396],[-88.78695,37.17858],[-88.79737,37.18485],[-88.83505,37.19649],[-88.86953,37.20971],[-88.9273,37.22636],[-88.93175,37.22759],[-88.98326,37.22868],[-89.00097,37.2244],[-89.07622,37.17513],[-89.08653,37.1656],[-89.10403,37.13197],[-89.11119,37.11905],[-89.15129,37.09049],[-89.1545,37.08891],[-89.17858,37.055],[-89.17938,37.05301],[-89.18248,37.03748],[-89.18251,37.03728],[-89.1736,37.01141],[-89.17112,37.00807],[-89.13844,36.98509],[-89.13301,36.982],[-89.1183,36.98188],[-89.11503,36.98033],[-89.09901,36.96139],[-89.09884,36.95785],[-89.13194,36.85744],[-89.13797,36.84735],[-89.17718,36.83578],[-89.17815,36.83459],[-89.17923,36.81291],[-89.17875,36.80993],[-89.17107,36.79812],[-89.16846,36.79557],[-89.13321,36.78823],[-89.12892,36.78768],[-89.11685,36.77561],[-89.11607,36.77242],[-89.12243,36.75484],[-89.12613,36.75173],[-89.15699,36.75597],[-89.16689,36.75963],[-89.19155,36.74722],[-89.19781,36.73941],[-89.20073,36.72014],[-89.19948,36.71605],[-89.17484,36.69396],[-89.16952,36.68888],[-89.16872,36.67189],[-89.15908,36.66635],[-89.18775,36.64111],[-89.19254,36.636],[-89.20261,36.60158],[-89.21356,36.58012],[-89.23184,36.56812],[-89.23654,36.56682],[-89.26806,36.56891],[-89.27171,36.57139],[-89.31943,36.62739],[-89.32472,36.63108],[-89.36486,36.62532],[-89.36555,36.62506]]],[[[-86.0832,38.00266],[-86.08252,37.80823],[-86.15172,37.79892],[-86.27537,37.5933],[-86.27184,37.58879],[-86.26139,37.58885],[-86.25214,37.59435],[-86.24634,37.59438],[-86.23343,37.58086],[-86.23221,37.57543],[-86.22002,37.57596],[-86.21075,37.57737],[-86.18677,37.56028],[-86.18035,37.55624],[-86.16999,37.56582],[-86.16419,37.56721],[-86.15428,37.56228],[-86.14613,37.5596],[-86.11425,37.56611],[-86.1131,37.56657],[-86.05621,37.4916],[-86.05151,37.48301],[-86.06584,37.46073],[-86.06756,37.458],[-86.05997,37.45123],[-86.05647,37.44853],[-86.05415,37.44899],[-86.05071,37.45354],[-86.00023,37.44696],[-85.8912,37.44011],[-85.89011,37.45144],[-85.89426,37.47002],[-85.88848,37.47366],[-85.87493,37.54533],[-85.83905,37.56901],[-85.82107,37.57404],[-85.80725,37.60173],[-85.7974,37.60855],[-85.80326,37.62032],[-85.80211,37.62305],[-85.73423,37.65674],[-85.68093,37.73207],[-85.65181,37.71806],[-85.6454,37.71308],[-85.63781,37.69632],[-85.63432,37.69406],[-85.60059,37.69908],[-85.59244,37.69364],[-85.6011,37.64604],[-85.60051,37.6397],[-85.58714,37.64469],[-85.58366,37.64424],[-85.57725,37.63926],[-85.57319,37.6379],[-85.57376,37.62838],[-85.56853,37.62295],[-85.57027,37.61751],[-85.57375,37.61705],[-85.57899,37.62611],[-85.58422,37.62566],[-85.5906,37.61613],[-85.59524,37.61341],[-85.61326,37.61612],[-85.615,37.61475],[-85.59464,37.59891],[-85.59464,37.59755],[-85.60219,37.59346],[-85.60683,37.59074],[-85.60564,37.57532],[-85.60505,37.56581],[-85.62302,37.55174],[-85.6265,37.54493],[-85.62417,37.5404],[-85.61778,37.54086],[-85.60735,37.54813],[-85.60212,37.54723],[-85.59341,37.54406],[-85.59514,37.53545],[-85.57134,37.5273],[-85.56495,37.52277],[-85.55393,37.53184],[-85.54697,37.53049],[-85.55105,37.5536],[-85.54408,37.56222],[-85.5348,37.56313],[-85.52667,37.56267],[-85.52144,37.55361],[-85.45053,37.68596],[-85.40147,37.73066],[-85.3873,37.7404],[-85.38629,37.74075],[-85.37373,37.73951],[-85.3733,37.73981],[-85.37495,37.76461],[-85.37454,37.7652],[-85.35546,37.75756],[-85.35345,37.75735],[-85.34591,37.76225],[-85.34548,37.76249],[-85.35624,37.78367],[-85.35601,37.78403],[-85.34029,37.78005],[-85.33859,37.77992],[-85.33649,37.78663],[-85.33574,37.78739],[-85.31214,37.79132],[-85.30818,37.79364],[-85.31532,37.80739],[-85.31527,37.80793],[-85.29908,37.83149],[-85.29844,37.83233],[-85.27861,37.83666],[-85.2776,37.83756],[-85.28027,37.85154],[-85.27953,37.85236],[-85.26827,37.84471],[-85.26784,37.84444],[-85.24567,37.84685],[-85.245,37.84689],[-85.25585,37.86503],[-85.25535,37.86583],[-85.24147,37.86229],[-85.24042,37.86243],[-85.23106,37.87044],[-85.23037,37.87061],[-85.22767,37.85492],[-85.22677,37.85501],[-85.21773,37.87142],[-85.21668,37.87141],[-85.21842,37.85492],[-85.21843,37.85427],[-85.20506,37.84608],[-85.20421,37.84624],[-85.20148,37.85319],[-85.19627,37.85603],[-85.20615,37.8633],[-85.19853,37.8728],[-85.1956,37.87642],[-85.19963,37.89003],[-85.199,37.90091],[-85.18916,37.88457],[-85.18683,37.88411],[-85.1868,37.8909],[-85.18446,37.89226],[-85.15766,37.88584],[-85.153,37.88583],[-85.15412,37.89535],[-85.15295,37.89762],[-85.14714,37.8908],[-85.13839,37.89168],[-85.13192,37.9039],[-85.12544,37.91566],[-85.10622,37.90926],[-85.10747,37.8934],[-85.09758,37.88974],[-85.09409,37.88792],[-85.03458,37.89224],[-85.0305,37.89177],[-85.03114,37.88316],[-85.03115,37.8818],[-85.01031,37.85951],[-85.00043,37.85448],[-85.0029,37.8341],[-85.00872,37.83503],[-85.01175,37.81736],[-85.00594,37.81643],[-85.02984,37.63114],[-85.03909,37.54505],[-85.01293,37.55084],[-85.00192,37.54807],[-85.00201,37.53312],[-84.89814,37.5322],[-84.74786,37.5853],[-84.75244,37.59213],[-84.73671,37.59656],[-84.73155,37.58973],[-84.71175,37.59505],[-84.71516,37.60232],[-84.69416,37.61035],[-84.68832,37.61258],[-84.69583,37.61716],[-84.69405,37.62032],[-84.65805,37.61826],[-84.65215,37.62548],[-84.65854,37.63503],[-84.65902,37.63541],[-84.66623,37.6334],[-84.66685,37.6341],[-84.65457,37.64052],[-84.65352,37.64113],[-84.65356,37.65231],[-84.6564,37.65442],[-84.67906,37.64593],[-84.68045,37.64496],[-84.67354,37.64198],[-84.67213,37.64074],[-84.6785,37.63672],[-84.68,37.6367],[-84.69459,37.64103],[-84.69491,37.64152],[-84.67925,37.65622],[-84.68039,37.65755],[-84.6929,37.66415],[-84.69376,37.66487],[-84.70234,37.65981],[-84.70524,37.66074],[-84.69935,37.66795],[-84.68009,37.67417],[-84.6823,37.68506],[-84.68343,37.68734],[-84.69628,37.68244],[-84.70036,37.68156],[-84.69848,37.69469],[-84.69845,37.69741],[-84.74265,37.69769],[-84.74322,37.69905],[-84.73286,37.70867],[-84.73258,37.70976],[-84.74578,37.71478],[-84.7442,37.71674],[-84.72678,37.71391],[-84.72444,37.71435],[-84.73072,37.72617],[-84.72836,37.72888],[-84.69934,37.72235],[-84.68998,37.72682],[-84.70564,37.73191],[-84.70737,37.73373],[-84.68813,37.73632],[-84.68865,37.74177],[-84.702,37.74548],[-84.70489,37.74777],[-84.69429,37.75903],[-84.69424,37.76356],[-84.71395,37.76793],[-84.71571,37.7696],[-84.70292,37.78664],[-84.70274,37.78751],[-84.71637,37.79979],[-84.71682,37.80026],[-84.71579,37.81518],[-84.71595,37.81553],[-84.67952,37.82987],[-84.6771,37.82838],[-84.67982,37.80132],[-84.6795,37.79834],[-84.66789,37.7834],[-84.66555,37.78298],[-84.64982,37.78901],[-84.64933,37.7907],[-84.65966,37.80897],[-84.65862,37.80952],[-84.61235,37.8017],[-84.61001,37.80071],[-84.60836,37.79271],[-84.60999,37.79165],[-84.64066,37.79291],[-84.64222,37.79201],[-84.64335,37.77918],[-84.64322,37.77846],[-84.60658,37.76066],[-84.60501,37.75974],[-84.61569,37.74642],[-84.61496,37.74584],[-84.60632,37.74281],[-84.60541,37.743],[-84.58968,37.75414],[-84.58728,37.75347],[-84.58816,37.73812],[-84.58776,37.73642],[-84.57019,37.72872],[-84.56928,37.72906],[-84.55705,37.74743],[-84.55591,37.74842],[-84.54004,37.75425],[-84.53923,37.75481],[-84.53656,37.76915],[-84.53602,37.76971],[-84.49641,37.78505],[-84.49565,37.78547],[-84.48348,37.80138],[-84.48291,37.80188],[-84.46464,37.79892],[-84.46412,37.79961],[-84.48413,37.83585],[-84.48467,37.83747],[-84.47809,37.85212],[-84.4773,37.85273],[-84.44594,37.84074],[-84.44411,37.84131],[-84.418,37.87157],[-84.41645,37.87212],[-84.39202,37.84668],[-84.39067,37.84596],[-84.37047,37.85387],[-84.36854,37.85455],[-84.38304,37.89289],[-84.38386,37.89473],[-84.37973,37.90109],[-84.37739,37.90174],[-84.34117,37.88224],[-84.34059,37.88272],[-84.33787,37.89163],[-84.33765,37.89193],[-84.34891,37.89836],[-84.34897,37.8986],[-84.33875,37.90712],[-84.33871,37.90733],[-84.34803,37.91488],[-84.34799,37.91512],[-84.33024,37.92249],[-84.32995,37.92392],[-84.33986,37.93097],[-84.33998,37.93131],[-84.33065,37.9368],[-84.3308,37.93723],[-84.33842,37.93906],[-84.33837,37.93921],[-84.31147,37.95185],[-84.31075,37.95217],[-84.32328,37.95589],[-84.32331,37.95603],[-84.31175,37.96302],[-84.31172,37.96332],[-84.32414,37.96579],[-84.32443,37.96645],[-84.31964,38.0023],[-84.28271,38.01912],[-84.29281,38.03333],[-84.29299,38.03361],[-84.28481,38.04006],[-84.28465,38.04043],[-84.28618,38.06663],[-84.28637,38.06701],[-84.08024,38.11516],[-84.02625,38.1526],[-83.99068,38.17484],[-83.9827,38.19287],[-83.98383,38.19515],[-83.97018,38.20314],[-83.96947,38.20948],[-83.98741,38.22013],[-83.98917,38.22015],[-83.9901,38.20293],[-83.99477,38.2039],[-84.00684,38.21538],[-84.0085,38.21993],[-84.04297,38.22488],[-84.06271,38.23463],[-84.06207,38.23689],[-84.05382,38.23906],[-84.05772,38.24953],[-84.05699,38.25722],[-84.06817,38.25509],[-84.07985,38.25704],[-84.07445,38.26378],[-84.07323,38.26603],[-84.07782,38.27107],[-84.08012,38.27336],[-84.08951,38.27301],[-84.09547,38.2681],[-84.09681,38.25905],[-84.10326,38.25912],[-84.10137,38.2659],[-84.10421,38.27046],[-84.11649,38.27242],[-84.11995,38.27517],[-84.10516,38.28271],[-84.1045,38.28633],[-84.11736,38.28829],[-84.12696,38.30789],[-84.13289,38.30478],[-84.16658,38.35501],[-84.19386,38.37162],[-84.10268,38.45943],[-84.10671,38.46884],[-84.10712,38.46916],[-84.13066,38.4746],[-84.13124,38.47465],[-84.131,38.48267],[-84.13163,38.48297],[-84.14244,38.47603],[-84.14319,38.47602],[-84.15141,38.48962],[-84.1521,38.48993],[-84.17199,38.4865],[-84.17319,38.48736],[-84.16006,38.50108],[-84.16124,38.50177],[-84.18289,38.49678],[-84.18345,38.49735],[-84.1794,38.52331],[-84.17804,38.53327],[-84.1643,38.54491],[-84.16177,38.55394],[-84.16816,38.559],[-84.20714,38.55125],[-84.20886,38.54992],[-84.21707,38.55729],[-84.21763,38.55813],[-84.20383,38.56432],[-84.20297,38.56516],[-84.20541,38.58206],[-84.20473,38.58794],[-84.19575,38.58834],[-84.1953,38.5883],[-84.20091,38.60377],[-84.2075,38.59749],[-84.23415,38.80739],[-84.23604,38.82232],[-84.23054,38.82744],[-84.23294,38.88603],[-84.23289,38.8871],[-84.2864,38.95228],[-84.28874,38.95567],[-84.30005,38.9935],[-84.30716,39.0073],[-84.33985,39.03437],[-84.34089,39.03501],[-84.42565,39.0527],[-84.42652,39.05322],[-84.43401,39.09569],[-84.43495,39.09977],[-84.45282,39.11925],[-84.45619,39.12054],[-84.4792,39.11807],[-84.48059,39.11742],[-84.50434,39.09592],[-84.50612,39.09511],[-84.54971,39.09972],[-84.55096,39.09949],[-84.57256,39.08215],[-84.57306,39.08191],[-84.61685,39.07323],[-84.61845,39.07327],[-84.65842,39.09552],[-84.65993,39.09614],[-84.68487,39.1003],[-84.68593,39.10077],[-84.71788,39.13641],[-84.71826,39.13682],[-84.75139,39.14753],[-84.75244,39.14726],[-84.7842,39.1179],[-84.7874,39.11544],[-84.83142,39.10085],[-84.83248,39.10036],[-84.89694,39.05747],[-84.89729,39.05747],[-84.83027,38.97417],[-84.83003,38.97305],[-84.83299,38.96042],[-84.83363,38.95943],[-84.8762,38.92254],[-84.87706,38.92147],[-84.87723,38.90954],[-84.87702,38.90901],[-84.8679,38.89921],[-84.86643,38.89871],[-84.8145,38.89546],[-84.81331,38.89523],[-84.78542,38.88075],[-84.78518,38.88001],[-84.78981,38.86206],[-84.79094,38.86057],[-84.82962,38.83112],[-84.82993,38.83037],[-84.81417,38.80034],[-84.81339,38.79851],[-84.81432,38.7847],[-84.8149,38.78428],[-84.88679,38.79463],[-84.88724,38.7948],[-84.93976,38.77602],[-84.94121,38.77565],[-84.99111,38.77842],[-84.99229,38.77815],[-85.10094,38.72662],[-85.10172,38.72651],[-85.13605,38.70062],[-85.1368,38.7001],[-85.17189,38.68836],[-85.17298,38.68807],[-85.21237,38.69501],[-85.21482,38.69625],[-85.2464,38.73147],[-85.24692,38.73194],[-85.2767,38.74135],[-85.27859,38.74159],[-85.36176,38.73051],[-85.3636,38.73037],[-85.41339,38.73683],[-85.41489,38.73677],[-85.43532,38.729],[-85.43609,38.7285],[-85.45169,38.71037],[-85.45184,38.7102],[-85.45673,38.68734],[-85.45665,38.68603],[-85.43897,38.65963],[-85.43854,38.65896],[-85.43832,38.60596],[-85.43824,38.60468],[-85.41528,38.55926],[-85.41489,38.55775],[-85.41777,38.53822],[-85.41777,38.53775],[-85.43188,38.52455],[-85.43291,38.52398],[-85.37901,38.51903],[-85.37859,38.51895],[-85.36594,38.50787],[-85.3657,38.5077],[-85.31944,38.49761],[-85.31592,38.49624],[-85.31416,38.49262],[-85.34598,38.45957],[-85.33133,38.44233],[-85.32496,38.4038],[-85.29568,38.37384],[-85.28281,38.35796],[-85.32459,38.30998],[-85.35159,38.30322],[-85.39057,38.30779],[-85.39323,38.30779],[-85.39558,38.30508],[-85.40906,38.30373],[-85.40791,38.29466],[-85.41025,38.29376],[-85.41318,38.29467],[-85.41669,38.30237],[-85.42255,38.30192],[-85.42666,38.30374],[-85.42491,38.29422],[-85.42725,38.29286],[-85.44718,38.30194],[-85.44894,38.3042],[-85.46127,38.28563],[-85.46713,38.28535],[-85.40596,38.26389],[-85.4051,38.26359],[-85.42905,38.11817],[-85.43035,38.10703],[-85.46195,38.09662],[-85.46954,38.09617],[-85.51222,38.01096],[-85.51689,38.01096],[-85.49995,37.99872],[-85.48886,37.99056],[-85.49995,37.98467],[-85.53381,37.96518],[-85.52563,37.95294],[-85.52972,37.94705],[-85.57987,37.91258],[-85.58395,37.91076],[-85.58042,37.88312],[-85.58683,37.87631],[-85.60548,37.87041],[-85.61364,37.86995],[-85.6107,37.85907],[-85.61828,37.85136],[-85.69802,37.81137],[-85.73414,37.81086],[-85.73833,37.81225],[-85.73833,37.84287],[-85.75207,37.84314],[-85.75241,37.87946],[-85.7737,37.87919],[-85.77541,37.97709],[-85.82382,37.9779],[-85.82399,37.99129],[-85.91154,37.99197],[-85.91171,38.00671],[-85.99891,37.99963],[-86.0305,37.99062],[-86.0317,37.96897],[-86.03703,37.95787],[-86.04904,37.95814],[-86.06569,37.97465],[-86.0832,38.00266]]]],"type":"MultiPolygon"}}, {"properties":{"name":"KyFromAbove Aerial Imagery (2018-2022)","id":"KYAPED_Phase_2","url":"https://kyraster.ky.gov/arcgis/services/ImageServices/Ky_KYAPED_Phase2_6IN_WGS84WM/ImageServer/WMSServer?LAYERS=0&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":false,"text":"KyFromAbove","url":"https://kyfromabove.ky.gov/"},"type":"wms","category":"photo","min_zoom":3,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[[-83.69079,36.58261],[-83.67433,36.60398],[-83.66336,36.60701],[-83.64681,36.62481],[-83.53182,36.66541],[-83.49345,36.67041],[-83.46347,36.66445],[-83.42102,36.66849],[-83.39584,36.67734],[-83.34788,36.7008],[-83.19272,36.74021],[-83.13511,36.74294],[-83.12551,36.76177],[-83.13247,36.76391],[-83.13505,36.78583],[-83.1233,36.78756],[-83.11155,36.80081],[-83.10429,36.8048],[-83.10273,36.81161],[-83.09907,36.81329],[-83.09937,36.82299],[-83.10225,36.82803],[-83.09901,36.83216],[-83.0911,36.83475],[-83.08804,36.83803],[-83.07512,36.84079],[-83.07587,36.85065],[-83.07271,36.85455],[-82.96652,36.86363],[-82.90734,36.87557],[-82.86855,36.89943],[-82.87869,36.90904],[-82.8589,36.92879],[-82.86334,36.94115],[-82.85957,36.95049],[-82.87449,36.96721],[-82.86718,36.97995],[-82.83834,36.98944],[-82.82882,37.00682],[-82.79135,37.0103],[-82.7598,37.0274],[-82.74841,37.02678],[-82.74367,37.04387],[-82.72287,37.04497],[-82.72663,37.07332],[-82.71747,37.07678],[-82.72419,37.08305],[-82.72676,37.11824],[-82.6547,37.15146],[-82.633,37.15476],[-82.61813,37.17024],[-82.50182,37.22621],[-82.43983,37.2474],[-82.34894,37.26799],[-82.34996,37.27216],[-82.3427,37.27402],[-82.34429,37.28125],[-82.32487,37.28335],[-82.31585,37.29493],[-82.1412,37.41613],[-82.06116,37.47223],[-82.04845,37.48241],[-82.01689,37.50386],[-81.96799,37.53804],[-81.96581,37.54067],[-81.96506,37.54339],[-81.97032,37.54676],[-81.97556,37.54603],[-81.98141,37.54202],[-81.98752,37.54301],[-81.98905,37.5428],[-81.98988,37.54212],[-81.99064,37.54049],[-81.99202,37.53879],[-81.99424,37.53771],[-81.99649,37.53823],[-81.99701,37.53948],[-81.9968,37.54081],[-81.99643,37.54174],[-81.99694,37.54308],[-81.99797,37.54335],[-82.00011,37.54252],[-82.00311,37.53851],[-82.00533,37.53501],[-82.00807,37.53311],[-82.01095,37.53279],[-82.01632,37.534],[-82.01687,37.53774],[-82.01792,37.53986],[-82.02021,37.54072],[-82.02684,37.53733],[-82.02976,37.53793],[-82.03394,37.5414],[-82.03678,37.54221],[-82.03787,37.54362],[-82.03865,37.54717],[-82.04016,37.5482],[-82.04376,37.5478],[-82.045,37.54579],[-82.04454,37.54163],[-82.04189,37.53487],[-82.04303,37.53057],[-82.04499,37.52798],[-82.04731,37.52804],[-82.04877,37.52928],[-82.04869,37.53397],[-82.05085,37.53564],[-82.05601,37.53672],[-82.0617,37.53589],[-82.06486,37.53721],[-82.06515,37.53891],[-82.06349,37.54269],[-82.06909,37.54951],[-82.07192,37.55097],[-82.07383,37.55556],[-82.08819,37.55571],[-82.09977,37.55279],[-82.10505,37.55269],[-82.10539,37.55433],[-82.10195,37.55842],[-82.10403,37.56011],[-82.11071,37.55873],[-82.1177,37.55918],[-82.12073,37.55621],[-82.12098,37.55437],[-82.12297,37.55156],[-82.12681,37.55109],[-82.13344,37.55261],[-82.13535,37.55752],[-82.13326,37.56039],[-82.13431,37.56334],[-82.14486,37.56681],[-82.14348,37.5708],[-82.12882,37.57234],[-82.12474,37.5763],[-82.13173,37.59287],[-82.14114,37.59504],[-82.14806,37.59033],[-82.15748,37.59238],[-82.15644,37.60538],[-82.15681,37.60959],[-82.16521,37.6076],[-82.16731,37.60781],[-82.16889,37.60868],[-82.16873,37.61023],[-82.1699,37.61316],[-82.16635,37.61685],[-82.1643,37.62019],[-82.1658,37.62048],[-82.16632,37.62109],[-82.16846,37.62176],[-82.17706,37.61789],[-82.18225,37.62235],[-82.18273,37.62531],[-82.18168,37.62721],[-82.17585,37.62987],[-82.17262,37.63217],[-82.17271,37.6341],[-82.17458,37.63561],[-82.17788,37.64114],[-82.175,37.64719],[-82.17702,37.64861],[-82.1859,37.6485],[-82.19108,37.64455],[-82.18775,37.63967],[-82.18572,37.62713],[-82.19228,37.62559],[-82.19928,37.62731],[-82.20556,37.62484],[-82.21445,37.62533],[-82.21602,37.6263],[-82.215,37.62778],[-82.22089,37.63464],[-82.21866,37.63684],[-82.21686,37.64166],[-82.22445,37.64475],[-82.22575,37.6528],[-82.24114,37.66179],[-82.25349,37.65638],[-82.25862,37.65666],[-82.26416,37.66063],[-82.27202,37.66388],[-82.27538,37.66879],[-82.27825,37.66986],[-82.28348,37.67632],[-82.28795,37.66803],[-82.29513,37.67063],[-82.295,37.67853],[-82.30271,37.67524],[-82.30495,37.67661],[-82.29594,37.68649],[-82.30322,37.69485],[-82.29633,37.70205],[-82.30089,37.70609],[-82.30693,37.70675],[-82.31133,37.71448],[-82.31138,37.71806],[-82.31617,37.72067],[-82.31944,37.73394],[-82.32688,37.73589],[-82.33428,37.74233],[-82.32774,37.74952],[-82.32169,37.75122],[-82.32099,37.75717],[-82.31745,37.76029],[-82.31169,37.76143],[-82.3123,37.76465],[-82.31718,37.76535],[-82.32572,37.76237],[-82.32924,37.76215],[-82.33435,37.76529],[-82.33365,37.76741],[-82.32307,37.77299],[-82.324,37.77504],[-82.32604,37.7758],[-82.33576,37.77393],[-82.33984,37.77628],[-82.33888,37.78236],[-82.34057,37.78591],[-82.34901,37.78674],[-82.35496,37.79315],[-82.36313,37.79437],[-82.36854,37.80108],[-82.37697,37.80207],[-82.37821,37.80382],[-82.37905,37.80886],[-82.38652,37.81807],[-82.38864,37.81767],[-82.39664,37.80855],[-82.40105,37.80856],[-82.40278,37.81247],[-82.39864,37.82174],[-82.39945,37.82954],[-82.409,37.83602],[-82.41309,37.84483],[-82.42,37.84574],[-82.42094,37.84756],[-82.41784,37.85107],[-82.41483,37.8561],[-82.42252,37.85917],[-82.42465,37.86094],[-82.42446,37.86305],[-82.42247,37.8641],[-82.40999,37.86571],[-82.40774,37.86713],[-82.40912,37.86861],[-82.41693,37.86913],[-82.41933,37.87248],[-82.41989,37.8846],[-82.4225,37.8865],[-82.428,37.88754],[-82.43311,37.89038],[-82.4341,37.89377],[-82.43809,37.90002],[-82.44762,37.90379],[-82.45164,37.90844],[-82.45978,37.90917],[-82.46345,37.91476],[-82.46756,37.91409],[-82.46874,37.91125],[-82.46801,37.90352],[-82.47123,37.89892],[-82.47466,37.89959],[-82.47667,37.90269],[-82.47442,37.90719],[-82.4756,37.91161],[-82.47905,37.91442],[-82.48218,37.91566],[-82.48715,37.91636],[-82.48853,37.91766],[-82.48822,37.91981],[-82.48054,37.9255],[-82.48166,37.92666],[-82.49681,37.92678],[-82.50229,37.93241],[-82.50258,37.93478],[-82.49951,37.93732],[-82.4911,37.93587],[-82.48968,37.93885],[-82.49416,37.9401],[-82.49771,37.94206],[-82.49798,37.94626],[-82.49507,37.94705],[-82.48758,37.94532],[-82.48111,37.94953],[-82.47168,37.95992],[-82.48499,37.96349],[-82.48503,37.97067],[-82.48232,37.97333],[-82.46901,37.97331],[-82.46471,37.97751],[-82.46489,37.98415],[-82.47262,37.98657],[-82.48293,37.98331],[-82.48491,37.98486],[-82.48642,37.98997],[-82.48608,37.99501],[-82.48827,37.99876],[-82.5001,37.99876],[-82.50865,38.00136],[-82.51357,37.99884],[-82.52002,38.00111],[-82.51549,38.006],[-82.51982,38.00789],[-82.52591,38.01798],[-82.52606,38.02627],[-82.53174,38.02904],[-82.53479,38.0318],[-82.53781,38.03535],[-82.53944,38.03873],[-82.53739,38.04508],[-82.54097,38.04727],[-82.54403,38.0522],[-82.54517,38.05519],[-82.54503,38.05887],[-82.54981,38.06347],[-82.54959,38.06839],[-82.55205,38.07102],[-82.55979,38.07252],[-82.56602,38.08094],[-82.57328,38.08148],[-82.58447,38.09066],[-82.58575,38.09479],[-82.58554,38.10653],[-82.58785,38.10894],[-82.59214,38.10995],[-82.59544,38.11257],[-82.59909,38.1169],[-82.60824,38.12075],[-82.61507,38.12],[-82.61945,38.12033],[-82.62131,38.12314],[-82.62212,38.13325],[-82.63683,38.13792],[-82.63862,38.14512],[-82.63878,38.15607],[-82.64514,38.16557],[-82.64265,38.17019],[-82.63953,38.17128],[-82.62739,38.17099],[-82.61942,38.16899],[-82.61267,38.1708],[-82.59996,38.19672],[-82.59852,38.21743],[-82.60915,38.22296],[-82.61303,38.23551],[-82.60866,38.24453],[-82.60482,38.24785],[-82.59331,38.24554],[-82.58491,38.24611],[-82.58117,38.2491],[-82.57481,38.26412],[-82.57464,38.27274],[-82.5797,38.28355],[-82.57958,38.29047],[-82.58353,38.29685],[-82.58042,38.30325],[-82.57313,38.31228],[-82.57184,38.31602],[-82.57322,38.31985],[-82.57568,38.32319],[-82.57688,38.32844],[-82.58494,38.33387],[-82.58947,38.34031],[-82.5964,38.34252],[-82.59879,38.34649],[-82.59764,38.36575],[-82.59433,38.372],[-82.59289,38.37576],[-82.59398,38.38041],[-82.60063,38.39053],[-82.59529,38.39869],[-82.59727,38.41033],[-82.59631,38.41801],[-82.61117,38.47165],[-82.65926,38.49435],[-82.69901,38.54244],[-82.73445,38.55813],[-82.78,38.55698],[-82.80279,38.56171],[-82.84487,38.58698],[-82.85608,38.6067],[-82.85998,38.66042],[-82.8812,38.68836],[-82.87425,38.70909],[-82.87353,38.74296],[-82.8926,38.75577],[-82.93408,38.74613],[-82.9691,38.72509],[-83.01796,38.72734],[-83.03037,38.72341],[-83.03792,38.70919],[-83.06106,38.6885],[-83.11184,38.67175],[-83.12449,38.63954],[-83.1477,38.61884],[-83.20603,38.61476],[-83.23751,38.6275],[-83.25861,38.62188],[-83.29212,38.59391],[-83.31665,38.60375],[-83.3269,38.63673],[-83.36863,38.65892],[-83.46197,38.66988],[-83.49081,38.69244],[-83.5311,38.70179],[-83.62774,38.67671],[-83.64669,38.63073],[-83.66827,38.62455],[-83.71719,38.64286],[-83.771,38.65327],[-83.78758,38.69931],[-83.84031,38.71442],[-83.84504,38.73796],[-83.86321,38.7585],[-83.92235,38.7683],[-83.95164,38.78456],[-83.96528,38.78624],[-84.03962,38.76914],[-84.08411,38.77016],[-84.14457,38.7896],[-84.20767,38.8004],[-84.228,38.81727],[-84.23744,38.8384],[-84.23294,38.88603],[-84.23289,38.8871],[-84.2864,38.95228],[-84.28874,38.95567],[-84.30005,38.9935],[-84.30716,39.0073],[-84.33985,39.03437],[-84.34089,39.03501],[-84.42565,39.0527],[-84.42652,39.05322],[-84.43401,39.09569],[-84.43495,39.09977],[-84.45282,39.11925],[-84.45619,39.12054],[-84.4792,39.11807],[-84.48059,39.11742],[-84.50434,39.09592],[-84.50612,39.09511],[-84.54971,39.09972],[-84.55096,39.09949],[-84.57256,39.08215],[-84.57306,39.08191],[-84.61685,39.07323],[-84.61845,39.07327],[-84.65842,39.09552],[-84.65993,39.09614],[-84.68487,39.1003],[-84.68593,39.10077],[-84.71788,39.13641],[-84.71826,39.13682],[-84.75139,39.14753],[-84.75244,39.14726],[-84.7842,39.1179],[-84.7874,39.11544],[-84.83142,39.10085],[-84.83248,39.10036],[-84.89694,39.05747],[-84.89729,39.05747],[-84.83027,38.97417],[-84.83003,38.97305],[-84.83299,38.96042],[-84.83363,38.95943],[-84.8762,38.92254],[-84.87706,38.92147],[-84.87723,38.90954],[-84.87702,38.90901],[-84.8679,38.89921],[-84.86643,38.89871],[-84.8145,38.89546],[-84.81331,38.89523],[-84.78542,38.88075],[-84.78518,38.88001],[-84.78981,38.86206],[-84.79094,38.86057],[-84.82962,38.83112],[-84.82993,38.83037],[-84.81417,38.80034],[-84.81339,38.79851],[-84.81432,38.7847],[-84.8149,38.78428],[-84.88679,38.79463],[-84.88724,38.7948],[-84.93976,38.77602],[-84.94121,38.77565],[-84.99111,38.77842],[-84.99229,38.77815],[-85.10094,38.72662],[-85.10172,38.72651],[-85.13605,38.70062],[-85.1368,38.7001],[-85.17189,38.68836],[-85.17298,38.68807],[-85.21237,38.69501],[-85.21482,38.69625],[-85.2464,38.73147],[-85.24692,38.73194],[-85.2767,38.74135],[-85.27859,38.74159],[-85.36176,38.73051],[-85.3636,38.73037],[-85.41339,38.73683],[-85.41489,38.73677],[-85.43532,38.729],[-85.43609,38.7285],[-85.45169,38.71037],[-85.45184,38.7102],[-85.45673,38.68734],[-85.45665,38.68603],[-85.43897,38.65963],[-85.43854,38.65896],[-85.43832,38.60596],[-85.43824,38.60468],[-85.41528,38.55926],[-85.41489,38.55775],[-85.41777,38.53822],[-85.41777,38.53775],[-85.43188,38.52455],[-85.43291,38.52398],[-85.46759,38.50802],[-85.48534,38.47536],[-85.51651,38.45602],[-85.58102,38.45038],[-85.61748,38.42559],[-85.64218,38.34231],[-85.67191,38.29922],[-85.75237,38.26101],[-85.78259,38.28633],[-85.81256,38.28285],[-85.83187,38.27071],[-85.83439,38.24867],[-85.84674,38.22249],[-85.8742,38.2077],[-85.89698,38.18329],[-85.90825,38.14643],[-85.90082,38.10483],[-85.92144,38.02204],[-85.94674,38.0039],[-85.99891,37.99963],[-86.0305,37.99062],[-86.0317,37.96897],[-86.03703,37.95787],[-86.04904,37.95814],[-86.06569,37.97465],[-86.0832,38.00266],[-86.10526,38.01108],[-86.13499,38.01429],[-86.17395,38.00779],[-86.22318,38.02719],[-86.23476,38.0364],[-86.26965,38.05557],[-86.2784,38.0719],[-86.2832,38.09757],[-86.27121,38.13587],[-86.29327,38.15831],[-86.31725,38.16727],[-86.34891,38.19526],[-86.36593,38.19762],[-86.37732,38.18735],[-86.37103,38.16411],[-86.3296,38.16067],[-86.31821,38.14634],[-86.33152,38.12729],[-86.38152,38.12549],[-86.39987,38.10266],[-86.44536,38.12595],[-86.46396,38.11808],[-86.46162,38.09946],[-86.43092,38.08672],[-86.4284,38.0702],[-86.44795,38.04886],[-86.52121,38.03914],[-86.52409,37.9765],[-86.50299,37.92998],[-86.5344,37.91343],[-86.58584,37.92175],[-86.59933,37.90652],[-86.59496,37.86403],[-86.62589,37.84367],[-86.65851,37.83913],[-86.6645,37.85579],[-86.64568,37.90557],[-86.67481,37.91466],[-86.72206,37.88816],[-86.74508,37.90217],[-86.77985,37.94719],[-86.79712,37.98841],[-86.81367,37.9971],[-86.84916,37.98784],[-86.91091,37.9365],[-86.9705,37.92866],[-87.00695,37.9192],[-87.04101,37.89479],[-87.03957,37.87113],[-87.06235,37.79878],[-87.09605,37.77916],[-87.13184,37.78058],[-87.13789,37.80617],[-87.16547,37.83761],[-87.21895,37.84391],[-87.29509,37.89318],[-87.34389,37.9086],[-87.40049,37.94057],[-87.44174,37.94114],[-87.50838,37.9045],[-87.52206,37.91325],[-87.53724,37.91882],[-87.54907,37.92401],[-87.55633,37.92803],[-87.56655,37.93649],[-87.57279,37.94837],[-87.57351,37.95173],[-87.57753,37.95168],[-87.57771,37.9678],[-87.59905,37.97139],[-87.60337,37.94984],[-87.61608,37.93603],[-87.6198,37.90879],[-87.58359,37.88466],[-87.57783,37.87207],[-87.60949,37.83155],[-87.64258,37.82369],[-87.67268,37.82682],[-87.68497,37.83884],[-87.68527,37.85655],[-87.66776,37.88788],[-87.68299,37.90094],[-87.72076,37.89053],[-87.74066,37.89346],[-87.76189,37.88977],[-87.78839,37.87416],[-87.83695,37.87643],[-87.88647,37.92438],[-87.90266,37.92449],[-87.93839,37.88627],[-87.90904,37.84833],[-87.89942,37.8091],[-87.92204,37.80074],[-87.95067,37.76792],[-87.99359,37.79118],[-88.04727,37.75139],[-88.13228,37.69126],[-88.15902,37.66098],[-88.15386,37.63117],[-88.12017,37.57132],[-88.07388,37.53796],[-88.05878,37.51019],[-88.06225,37.48802],[-88.0824,37.47147],[-88.28132,37.45148],[-88.32401,37.43225],[-88.34296,37.41263],[-88.36547,37.40166],[-88.37121,37.40273],[-88.40624,37.42479],[-88.40881,37.42522],[-88.46586,37.40055],[-88.47022,37.39625],[-88.48672,37.34015],[-88.48695,37.3396],[-88.51406,37.29246],[-88.51486,37.29069],[-88.50409,37.26514],[-88.50382,37.26485],[-88.5123,37.26295],[-88.51187,37.26201],[-88.45005,37.2062],[-88.44982,37.20599],[-88.42533,37.15421],[-88.42462,37.15173],[-88.44912,37.08875],[-88.44919,37.08776],[-88.45919,37.07523],[-88.46019,37.07447],[-88.48622,37.06659],[-88.48605,37.0648],[-88.56528,37.07521],[-88.56587,37.0752],[-88.62221,37.11775],[-88.62589,37.11946],[-88.68777,37.13938],[-88.69398,37.14115],[-88.73125,37.14368],[-88.73211,37.14396],[-88.78695,37.17858],[-88.79737,37.18485],[-88.83505,37.19649],[-88.86953,37.20971],[-88.9273,37.22636],[-88.93175,37.22759],[-88.98326,37.22868],[-89.00097,37.2244],[-89.07622,37.17513],[-89.08653,37.1656],[-89.10403,37.13197],[-89.11119,37.11905],[-89.15129,37.09049],[-89.1545,37.08891],[-89.17858,37.055],[-89.17938,37.05301],[-89.18248,37.03748],[-89.18251,37.03728],[-89.1736,37.01141],[-89.17112,37.00807],[-89.13844,36.98509],[-89.13301,36.982],[-89.1183,36.98188],[-89.11503,36.98033],[-89.09901,36.96139],[-89.09884,36.95785],[-89.13194,36.85744],[-89.13797,36.84735],[-89.17718,36.83578],[-89.17815,36.83459],[-89.17923,36.81291],[-89.17875,36.80993],[-89.17107,36.79812],[-89.16846,36.79557],[-89.13321,36.78823],[-89.12892,36.78768],[-89.11685,36.77561],[-89.11607,36.77242],[-89.12243,36.75484],[-89.12613,36.75173],[-89.15699,36.75597],[-89.16689,36.75963],[-89.19155,36.74722],[-89.19781,36.73941],[-89.20073,36.72014],[-89.19948,36.71605],[-89.17484,36.69396],[-89.16952,36.68888],[-89.16872,36.67189],[-89.15908,36.66635],[-89.18775,36.64111],[-89.19254,36.636],[-89.20261,36.60158],[-89.21356,36.58012],[-89.23184,36.56812],[-89.23654,36.56682],[-89.26806,36.56891],[-89.27171,36.57139],[-89.31943,36.62739],[-89.32472,36.63108],[-89.36486,36.62532],[-89.36555,36.62506],[-89.37545,36.61572],[-89.37637,36.61387],[-89.41729,36.49903],[-89.34795,36.50308],[-89.30028,36.50715],[-88.06598,36.49774],[-88.05332,36.49712],[-88.0453,36.50408],[-88.03948,36.51041],[-88.03413,36.53112],[-88.03249,36.54066],[-88.0412,36.58412],[-88.04513,36.60294],[-88.06821,36.65975],[-88.07053,36.67812],[-87.85045,36.6651],[-87.85355,36.63303],[-87.81577,36.63427],[-87.81886,36.73826],[-87.40945,36.74484],[-87.40717,36.64113],[-86.9982,36.64425],[-86.58995,36.65243],[-86.56427,36.63359],[-86.50781,36.65238],[-86.41587,36.65103],[-86.36545,36.64996],[-86.33208,36.64871],[-86.29245,36.64527],[-86.19791,36.63973],[-86.12894,36.63612],[-85.83242,36.62211],[-85.78445,36.62202],[-85.67737,36.61841],[-85.50117,36.615],[-85.33222,36.62327],[-85.3255,36.62472],[-85.3002,36.62443],[-85.29337,36.62635],[-85.19552,36.62539],[-85.11243,36.62299],[-84.99612,36.61789],[-84.93593,36.61173],[-84.82297,36.60403],[-84.54335,36.59594],[-84.44599,36.59671],[-84.0503,36.59093],[-83.82598,36.58477],[-83.78356,36.5839],[-83.69079,36.58261]]],[[[-89.55251,36.57723],[-89.55264,36.57718],[-89.57151,36.55257],[-89.54296,36.50496],[-89.53912,36.4981],[-89.4885,36.49755],[-89.4852,36.49745],[-89.46589,36.52995],[-89.46545,36.53616],[-89.4808,36.56969],[-89.48089,36.56977],[-89.5205,36.57943],[-89.52234,36.58018],[-89.55251,36.57723]]]],"type":"MultiPolygon"}}, {"properties":{"name":"MassGIS 2019 Orthos","id":"MassGIS-2019-Orthos","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/USGS_Orthos_2019/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/info-details/massgis-data-2019-aerial-imagery"},"type":"tms","category":"photo","min_zoom":7,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, -{"properties":{"name":"MassGIS LIDAR Shaded Relief","id":"MassGIS-LIDAR-Shaded-Relief","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/LiDAR_ShadedRelief/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/info-details/massgis-data-lidar-terrain-data"},"type":"tms","category":"elevation","min_zoom":6,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, +{"properties":{"name":"MassGIS LIDAR Shaded Relief","id":"MassGIS-LIDAR-Shaded-Relief","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/LiDAR_ShadedRelief_18Nant_21EC/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/info-details/massgis-data-lidar-terrain-data"},"type":"tms","category":"elevation","min_zoom":7,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, +{"properties":{"name":"MassGIS LIDAR Slope","id":"MassGIS-LIDAR-Slope","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/Slope_Grayscale_2013to2021/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/info-details/massgis-data-lidar-terrain-data"},"type":"tms","category":"elevation","min_zoom":7,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, {"properties":{"name":"MassGIS 2021 Aerial Imagery","id":"MassGIS_2021_Aerial","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/orthos2021/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/info-details/massgis-data-2021-aerial-imagery"},"type":"tms","category":"photo","max_zoom":20,"best":true},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, {"properties":{"name":"MassGIS Basemap","id":"MassGIS-basemap","url":"https://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/MassGISBasemap/MapServer/tile/{zoom}/{y}/{x}","attribution":{"required":false,"text":"MassGIS","url":"https://www.mass.gov/service-details/massgis-base-map"},"type":"tms","category":"map","min_zoom":7,"max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-72.13569,42.03025],[-72.0635,42.02735],[-71.80067,42.02351],[-71.79925,42.00807],[-71.52888,42.01499],[-71.49744,42.01725],[-71.38127,42.01885],[-71.38174,41.8932],[-71.33865,41.89865],[-71.34086,41.87872],[-71.33392,41.86229],[-71.3422,41.8448],[-71.3352,41.8355],[-71.3449,41.828],[-71.3472,41.8231],[-71.33914,41.80842],[-71.34156,41.79817],[-71.33407,41.79455],[-71.32885,41.7811],[-71.26139,41.7523],[-71.1954,41.67514],[-71.17588,41.67154],[-71.17605,41.6681],[-71.13291,41.6601],[-71.13569,41.6284],[-71.14047,41.62389],[-71.14059,41.6051],[-71.13131,41.59231],[-71.12047,41.49717],[-71.09996,41.43386],[-70.81959,41.23192],[-69.89537,41.21643],[-69.88713,42.0519],[-70.8759,42.35302],[-70.45842,42.67694],[-70.81567,42.87204],[-70.82963,42.86875],[-70.84776,42.86088],[-70.88566,42.88288],[-70.90348,42.88671],[-70.91465,42.88661],[-70.92973,42.88504],[-70.94967,42.87588],[-70.96702,42.86887],[-71.03128,42.85924],[-71.04483,42.84869],[-71.05395,42.83337],[-71.06442,42.80626],[-71.13277,42.82145],[-71.16667,42.80891],[-71.18617,42.79088],[-71.18181,42.73732],[-71.22391,42.74643],[-71.23732,42.74491],[-71.24598,42.74231],[-71.25526,42.73659],[-71.26787,42.72603],[-71.27894,42.71136],[-71.29464,42.69704],[-71.69663,42.70572],[-71.97286,42.71307],[-72.6872,42.73348],[-73.26496,42.74594],[-73.50814,42.08626],[-73.49688,42.04968],[-73.43281,42.05059],[-73.03678,42.03929],[-72.81378,42.03674],[-72.81705,41.99769],[-72.76673,42.00327],[-72.76572,42.02276],[-72.75868,42.02439],[-72.75714,42.03635],[-72.69933,42.03696],[-72.64019,42.03205],[-72.60797,42.03108],[-72.60717,42.02515],[-72.58216,42.02474],[-72.57278,42.03022],[-72.53156,42.03458],[-72.13569,42.03025]]],"type":"Polygon"}}, {"properties":{"name":"MD Latest 6 Inch Aerial Imagery","id":"geodata.md.gov-MD_SixInchImagery","url":"https://geodata.md.gov/imap/rest/services/Imagery/MD_SixInchImagery/ImageServer/exportImage?f=image&format=jpg&imageSR={wkid}&bboxSR={wkid}&bbox={bbox}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"DoIT, MD iMap, MDP","url":"https://imap.maryland.gov/Pages/imagery-products.aspx"},"type":"wms","category":"photo","max_zoom":20,"best":true},"type":"Feature","geometry":{"coordinates":[[[-76.68182,38.2309],[-76.23413,37.92037],[-75.86369,37.90953],[-75.77897,37.96538],[-75.73563,37.96247],[-75.65551,37.95295],[-75.64177,37.97654],[-75.63825,37.97935],[-75.6364,37.97962],[-75.63186,37.97539],[-75.62967,37.97583],[-75.62924,37.97712],[-75.63405,37.98334],[-75.63344,37.98581],[-75.63053,37.98801],[-75.62666,37.98882],[-75.62448,37.99413],[-75.23865,38.02692],[-75.187,38.09755],[-75.09773,38.30907],[-75.08151,38.32321],[-75.04984,38.40222],[-75.04844,38.4515],[-75.3717,38.45251],[-75.69099,38.46058],[-75.78644,39.6546],[-75.78839,39.72236],[-77.72441,39.72178],[-78.16762,39.72239],[-78.29428,39.72282],[-78.31703,39.723],[-78.35335,39.7227],[-78.38831,39.72287],[-78.61083,39.72298],[-78.71839,39.72311],[-78.82587,39.72306],[-79.04114,39.72298],[-79.4775,39.72141],[-79.48316,39.53264],[-79.48977,39.20526],[-79.47184,39.20113],[-79.42394,39.22334],[-79.35897,39.27313],[-79.28936,39.29711],[-79.21177,39.36217],[-79.16147,39.38739],[-79.11015,39.43129],[-79.08959,39.46048],[-79.06929,39.4734],[-79.03058,39.46323],[-78.9602,39.43526],[-78.87437,39.52238],[-78.81472,39.56223],[-78.77953,39.63716],[-78.77599,39.64415],[-78.76599,39.64681],[-78.76717,39.64291],[-78.7791,39.62509],[-78.77927,39.62103],[-78.76341,39.61814],[-78.74773,39.62526],[-78.73768,39.62156],[-78.73472,39.61494],[-78.7394,39.61025],[-78.74232,39.61002],[-78.74704,39.60774],[-78.75026,39.61048],[-78.76146,39.61131],[-78.7785,39.60582],[-78.77858,39.60053],[-78.76601,39.58509],[-78.75618,39.57999],[-78.74455,39.57897],[-78.74245,39.58022],[-78.73979,39.58581],[-78.73425,39.58552],[-78.73283,39.5751],[-78.72494,39.56229],[-78.70734,39.55538],[-78.68979,39.54548],[-78.67571,39.53992],[-78.65361,39.53344],[-78.60589,39.53158],[-78.56581,39.51881],[-78.52718,39.5202],[-78.47002,39.51411],[-78.46272,39.51854],[-78.45788,39.52344],[-78.45805,39.53463],[-78.45037,39.53767],[-78.43655,39.53807],[-78.41732,39.54562],[-78.39483,39.58241],[-78.39355,39.58568],[-78.39535,39.59101],[-78.42504,39.60913],[-78.43195,39.61835],[-78.42925,39.62225],[-78.42204,39.62341],[-78.38741,39.60823],[-78.37638,39.60595],[-78.37149,39.61005],[-78.37071,39.6129],[-78.382,39.62334],[-78.3805,39.62787],[-78.37423,39.62899],[-78.3593,39.62414],[-78.35277,39.62704],[-78.35119,39.63012],[-78.35621,39.63597],[-78.35651,39.63838],[-78.35282,39.63957],[-78.33887,39.63676],[-78.2842,39.61911],[-78.26566,39.61673],[-78.25201,39.63921],[-78.22283,39.66042],[-78.22235,39.6623],[-78.22575,39.66614],[-78.23201,39.67178],[-78.22793,39.67495],[-78.20236,39.67588],[-78.18283,39.69348],[-78.17674,39.69517],[-78.11331,39.68024],[-78.08979,39.67099],[-78.04816,39.64066],[-78.01177,39.60258],[-78.00688,39.6002],[-77.97375,39.59795],[-77.96474,39.60509],[-77.95753,39.60675],[-77.9528,39.60324],[-77.95289,39.58538],[-77.94336,39.58353],[-77.93624,39.58677],[-77.93384,39.60959],[-77.93946,39.61455],[-77.94281,39.61511],[-77.94259,39.61756],[-77.93834,39.61848],[-77.93405,39.61782],[-77.92937,39.61349],[-77.92641,39.60618],[-77.92336,39.6041],[-77.89564,39.59597],[-77.88337,39.59775],[-77.87938,39.6006],[-77.87981,39.60562],[-77.88487,39.61468],[-77.87397,39.61256],[-77.8662,39.60817],[-77.83822,39.60463],[-77.83058,39.59154],[-77.8371,39.56891],[-77.88423,39.56375],[-77.89092,39.55733],[-77.88774,39.55091],[-77.86714,39.5388],[-77.86697,39.51497],[-77.86131,39.51285],[-77.84303,39.51556],[-77.83848,39.52007],[-77.83702,39.53072],[-77.82637,39.5286],[-77.82432,39.52364],[-77.82749,39.51642],[-77.84629,39.50662],[-77.84912,39.50238],[-77.84706,39.49775],[-77.82749,39.49218],[-77.80088,39.48821],[-77.79003,39.4902],[-77.78479,39.49652],[-77.7814,39.49838],[-77.77406,39.49864],[-77.76943,39.49735],[-77.76698,39.49513],[-77.76707,39.49238],[-77.77033,39.49053],[-77.78827,39.48609],[-77.79797,39.48185],[-77.79951,39.47516],[-77.79719,39.47079],[-77.77908,39.46247],[-77.78067,39.46118],[-77.79844,39.46294],[-77.79998,39.45727],[-77.79616,39.45266],[-77.78595,39.44637],[-77.79028,39.44309],[-77.8011,39.4413],[-77.80535,39.43762],[-77.80088,39.43172],[-77.75454,39.42207],[-77.73668,39.38928],[-77.75316,39.384],[-77.75411,39.37896],[-77.74424,39.3631],[-77.74539,39.3564],[-77.74896,39.35089],[-77.7611,39.34518],[-77.76166,39.34014],[-77.75848,39.33476],[-77.75415,39.3329],[-77.72703,39.32155],[-77.71437,39.32268],[-77.70613,39.32198],[-77.69795,39.31914],[-77.69349,39.31883],[-77.68836,39.31986],[-77.68136,39.32553],[-77.67561,39.32573],[-77.67257,39.32304],[-77.66347,39.31723],[-77.64761,39.31194],[-77.63765,39.30885],[-77.63223,39.30873],[-77.62306,39.30581],[-77.60459,39.30403],[-77.59422,39.30277],[-77.58541,39.30425],[-77.57429,39.30721],[-77.56749,39.30742],[-77.56335,39.30571],[-77.55996,39.30166],[-77.55972,39.29601],[-77.56137,39.28841],[-77.55798,39.28401],[-77.55324,39.28145],[-77.54981,39.27628],[-77.54215,39.27059],[-77.53972,39.26808],[-77.53704,39.26485],[-77.53266,39.26256],[-77.52065,39.25866],[-77.52017,39.25774],[-77.51846,39.25689],[-77.51186,39.25385],[-77.50882,39.25272],[-77.50509,39.25208],[-77.50345,39.25206],[-77.49978,39.25145],[-77.49646,39.25146],[-77.48713,39.24748],[-77.48481,39.24616],[-77.48392,39.24494],[-77.48279,39.24408],[-77.4808,39.24154],[-77.47892,39.24023],[-77.4781,39.24045],[-77.47119,39.23518],[-77.45692,39.22745],[-77.45578,39.22369],[-77.45715,39.21977],[-77.47138,39.20891],[-77.47348,39.20363],[-77.47357,39.19332],[-77.4755,39.19049],[-77.47915,39.18743],[-77.48425,39.18523],[-77.50322,39.18141],[-77.50846,39.17925],[-77.51425,39.17242],[-77.52395,39.1487],[-77.52697,39.14666],[-77.52698,39.14344],[-77.52608,39.13532],[-77.52417,39.12883],[-77.5226,39.12525],[-77.52048,39.1218],[-77.5182,39.12019],[-77.51427,39.11871],[-77.50672,39.11764],[-77.48702,39.11223],[-77.48001,39.10757],[-77.47481,39.10147],[-77.47159,39.09476],[-77.46772,39.08884],[-77.46879,39.08658],[-77.46881,39.08574],[-77.46831,39.08497],[-77.46531,39.08156],[-77.46389,39.07957],[-77.46318,39.07854],[-77.46228,39.07631],[-77.46089,39.07513],[-77.45726,39.07359],[-77.45264,39.07255],[-77.44928,39.0724],[-77.44404,39.07149],[-77.44179,39.07144],[-77.43791,39.07096],[-77.43355,39.07014],[-77.42883,39.06885],[-77.42237,39.06758],[-77.41278,39.06656],[-77.40448,39.0655],[-77.3978,39.06546],[-77.3872,39.06383],[-77.33345,39.06458],[-77.33364,39.05958],[-77.32842,39.05798],[-77.32336,39.05607],[-77.32009,39.05545],[-77.31727,39.05403],[-77.31516,39.05251],[-77.31255,39.052],[-77.3058,39.05272],[-77.29118,39.04613],[-77.2739,39.03452],[-77.25103,39.02913],[-77.24582,39.02585],[-77.24286,39.02095],[-77.24519,39.0148],[-77.25346,39.00658],[-77.2535,38.99696],[-77.25236,38.99568],[-77.24987,38.99466],[-77.24822,38.99179],[-77.24536,38.98438],[-77.24438,38.98278],[-77.2391,38.98081],[-77.23511,38.97699],[-77.23191,38.98023],[-77.2293,38.98032],[-77.22419,38.97373],[-77.2193,38.9719],[-77.21133,38.97022],[-77.20535,38.9706],[-77.20028,38.96889],[-77.17394,38.96885],[-77.17025,38.96721],[-77.16608,38.96833],[-77.1595,38.96627],[-77.14899,38.96611],[-77.14273,38.96329],[-77.13647,38.95784],[-77.12904,38.94743],[-77.12718,38.94109],[-77.11953,38.93452],[-77.04097,38.99592],[-76.90966,38.89285],[-77.03944,38.79151],[-77.04128,38.70775],[-77.10995,38.68671],[-77.12488,38.67077],[-77.12042,38.63444],[-77.24024,38.58414],[-77.29912,38.46972],[-77.28762,38.39576],[-77.26152,38.35929],[-77.2229,38.34731],[-77.02635,38.42213],[-76.94,38.27053],[-76.74465,38.20527],[-76.68182,38.2309]]],"type":"Polygon"}}, @@ -586,7 +594,7 @@ {"properties":{"name":"Dakota County GIS 2019 Spring Leaf-Off 6-Inch","id":"DCGIS-County-Imagery-2019-Spring-Leaf-Off-6-Inch","url":"https://gisimg.co.dakota.mn.us/arcgis/services/AerialPhotography/2019AirPhotoLeafOff6Inch_Spring/ImageServer/WMSServer?LAYERS=2019AirPhotoLeafOff6Inch_Spring:default&STYLES=&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":false,"text":"Dakota County GIS","url":"https://dakotacounty.us"},"type":"wms","category":"photo","min_zoom":5,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-93.32967,44.79107],[-93.32964,44.63037],[-93.28189,44.63074],[-93.28169,44.47194],[-93.28176,44.47137],[-93.0395,44.47103],[-93.03924,44.51125],[-92.91932,44.51049],[-92.91899,44.54325],[-92.79268,44.54324],[-92.7926,44.62971],[-92.73207,44.62948],[-92.73122,44.71411],[-92.80342,44.74652],[-92.82767,44.75056],[-92.85209,44.74695],[-92.85959,44.75359],[-92.87724,44.77283],[-92.88149,44.77492],[-92.9049,44.77408],[-92.92808,44.78111],[-92.93969,44.77563],[-92.94843,44.76786],[-92.95859,44.76724],[-92.98604,44.77501],[-92.99291,44.77517],[-93.00306,44.77206],[-93.01685,44.77635],[-93.02153,44.79431],[-93.00523,44.81541],[-93.0119,44.83657],[-93.00859,44.85652],[-93.01041,44.86586],[-93.02074,44.89279],[-93.0309,44.8967],[-93.04083,44.90391],[-93.04445,44.91514],[-93.04725,44.9195],[-93.04724,44.92318],[-93.12863,44.92335],[-93.12882,44.91965],[-93.13257,44.91243],[-93.1641,44.89048],[-93.18289,44.8872],[-93.20075,44.86486],[-93.20325,44.85263],[-93.22179,44.83825],[-93.25188,44.81146],[-93.28177,44.80611],[-93.30453,44.7945],[-93.32645,44.79245],[-93.32961,44.79107],[-93.32967,44.79107]]],"type":"Polygon"}}, {"properties":{"name":"Hennepin County Orthoimagery (2020)","id":"Hennepin_Ortho_2020","url":"https://gis.hennepin.us/arcgis/services/Imagery/UTM_Aerial_2020/MapServer/WMSServer?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=1&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":false,"text":"Hennepin County GIS","url":"https://gis-hennepin.hub.arcgis.com/"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-93.20054,44.86147],[-93.1781,44.8865],[-93.17243,44.88651],[-93.17245,44.89458],[-93.18381,44.89456],[-93.18382,44.8986],[-93.18951,44.89859],[-93.18952,44.90666],[-93.19521,44.90665],[-93.19534,44.947],[-93.2018,44.94696],[-93.20189,44.95506],[-93.20673,44.95505],[-93.20702,45.03576],[-93.28101,45.03561],[-93.28115,45.06788],[-93.27548,45.06789],[-93.27566,45.10824],[-93.28136,45.10823],[-93.28137,45.10984],[-93.28426,45.10984],[-93.28427,45.11226],[-93.28708,45.11225],[-93.28711,45.11629],[-93.2928,45.11629],[-93.29289,45.13241],[-93.29858,45.1324],[-93.2986,45.13643],[-93.3043,45.13642],[-93.30491,45.14448],[-93.31005,45.14447],[-93.31007,45.14851],[-93.32147,45.14848],[-93.3215,45.15251],[-93.3272,45.1525],[-93.32723,45.15653],[-93.33863,45.1565],[-93.33866,45.16053],[-93.34436,45.16051],[-93.3444,45.16762],[-93.34599,45.16762],[-93.34599,45.16858],[-93.35011,45.16857],[-93.35014,45.1726],[-93.35585,45.17258],[-93.35586,45.17662],[-93.36158,45.17661],[-93.3616,45.18064],[-93.37301,45.18061],[-93.37304,45.18464],[-93.37874,45.18462],[-93.37877,45.18865],[-93.39018,45.18863],[-93.39021,45.19265],[-93.39591,45.19263],[-93.39594,45.19642],[-93.40762,45.1964],[-93.40767,45.20066],[-93.41309,45.20064],[-93.41315,45.20871],[-93.41886,45.20869],[-93.41892,45.21676],[-93.42463,45.21674],[-93.42466,45.22077],[-93.4532,45.22066],[-93.45323,45.2247],[-93.45894,45.22468],[-93.45898,45.22871],[-93.48753,45.22859],[-93.48756,45.23262],[-93.49327,45.2326],[-93.49334,45.24067],[-93.49905,45.24065],[-93.49909,45.24469],[-93.5048,45.24466],[-93.50484,45.24869],[-93.52768,45.24859],[-93.52761,45.24052],[-93.5219,45.24056],[-93.52187,45.23651],[-93.52757,45.23648],[-93.5275,45.22841],[-93.53321,45.22839],[-93.53325,45.23242],[-93.53896,45.2324],[-93.539,45.23643],[-93.54471,45.2364],[-93.54467,45.23237],[-93.55037,45.23234],[-93.55034,45.22831],[-93.56176,45.22825],[-93.56172,45.22422],[-93.57313,45.22417],[-93.5731,45.22012],[-93.59593,45.22001],[-93.59585,45.21194],[-93.60155,45.21191],[-93.6016,45.21594],[-93.61302,45.21588],[-93.61298,45.21185],[-93.64722,45.21166],[-93.64713,45.20359],[-93.65284,45.20355],[-93.65279,45.19952],[-93.6585,45.19949],[-93.65846,45.19545],[-93.66416,45.19542],[-93.66407,45.18735],[-93.65836,45.18739],[-93.65831,45.18335],[-93.65261,45.18338],[-93.65256,45.17935],[-93.64686,45.17938],[-93.64682,45.17535],[-93.64111,45.17538],[-93.64102,45.16731],[-93.64672,45.16728],[-93.64667,45.16324],[-93.65238,45.16321],[-93.65233,45.15917],[-93.65803,45.15914],[-93.65799,45.15511],[-93.6865,45.15494],[-93.68641,45.14687],[-93.69211,45.14683],[-93.69206,45.1428],[-93.69776,45.14276],[-93.69771,45.13873],[-93.70341,45.13869],[-93.70336,45.13466],[-93.70906,45.13462],[-93.70896,45.12655],[-93.71409,45.12652],[-93.71404,45.12245],[-93.72031,45.12241],[-93.72026,45.11841],[-93.72596,45.11838],[-93.72581,45.10627],[-93.7315,45.10623],[-93.7313,45.09009],[-93.73699,45.09006],[-93.73694,45.08602],[-93.74264,45.08599],[-93.74258,45.08195],[-93.75397,45.08188],[-93.75405,45.08591],[-93.76542,45.08584],[-93.7652,45.0697],[-93.7709,45.06966],[-93.76851,44.8903],[-93.60927,44.89126],[-93.60925,44.88905],[-93.52439,44.88947],[-93.52365,44.80364],[-93.43786,44.80979],[-93.34477,44.78525],[-93.24592,44.81373],[-93.20054,44.86147]]],"type":"Polygon"}}, {"properties":{"name":"Hennepin County Orthoimagery (2021)","id":"Hennepin_Ortho_2021","url":"https://gis.hennepin.us/arcgis/services/Imagery/UTM_Aerial_2021/MapServer/WMSServer?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=1&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":false,"text":"Hennepin County GIS","url":"https://gis-hennepin.hub.arcgis.com/"},"type":"wms","category":"historicphoto","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-93.20054,44.86147],[-93.1781,44.8865],[-93.17243,44.88651],[-93.17245,44.89458],[-93.18381,44.89456],[-93.18382,44.8986],[-93.18951,44.89859],[-93.18952,44.90666],[-93.19521,44.90665],[-93.19534,44.947],[-93.2018,44.94696],[-93.20189,44.95506],[-93.20673,44.95505],[-93.20702,45.03576],[-93.28101,45.03561],[-93.28115,45.06788],[-93.27548,45.06789],[-93.27566,45.10824],[-93.28136,45.10823],[-93.28137,45.10984],[-93.28426,45.10984],[-93.28427,45.11226],[-93.28708,45.11225],[-93.28711,45.11629],[-93.2928,45.11629],[-93.29289,45.13241],[-93.29858,45.1324],[-93.2986,45.13643],[-93.3043,45.13642],[-93.30491,45.14448],[-93.31005,45.14447],[-93.31007,45.14851],[-93.32147,45.14848],[-93.3215,45.15251],[-93.3272,45.1525],[-93.32723,45.15653],[-93.33863,45.1565],[-93.33866,45.16053],[-93.34436,45.16051],[-93.3444,45.16762],[-93.34599,45.16762],[-93.34599,45.16858],[-93.35011,45.16857],[-93.35014,45.1726],[-93.35585,45.17258],[-93.35586,45.17662],[-93.36158,45.17661],[-93.3616,45.18064],[-93.37301,45.18061],[-93.37304,45.18464],[-93.37874,45.18462],[-93.37877,45.18865],[-93.39018,45.18863],[-93.39021,45.19265],[-93.39591,45.19263],[-93.39594,45.19642],[-93.40762,45.1964],[-93.40767,45.20066],[-93.41309,45.20064],[-93.41315,45.20871],[-93.41886,45.20869],[-93.41892,45.21676],[-93.42463,45.21674],[-93.42466,45.22077],[-93.4532,45.22066],[-93.45323,45.2247],[-93.45894,45.22468],[-93.45898,45.22871],[-93.48753,45.22859],[-93.48756,45.23262],[-93.49327,45.2326],[-93.49334,45.24067],[-93.49905,45.24065],[-93.49909,45.24469],[-93.5048,45.24466],[-93.50484,45.24869],[-93.52768,45.24859],[-93.52761,45.24052],[-93.5219,45.24056],[-93.52187,45.23651],[-93.52757,45.23648],[-93.5275,45.22841],[-93.53321,45.22839],[-93.53325,45.23242],[-93.53896,45.2324],[-93.539,45.23643],[-93.54471,45.2364],[-93.54467,45.23237],[-93.55037,45.23234],[-93.55034,45.22831],[-93.56176,45.22825],[-93.56172,45.22422],[-93.57313,45.22417],[-93.5731,45.22012],[-93.59593,45.22001],[-93.59585,45.21194],[-93.60155,45.21191],[-93.6016,45.21594],[-93.61302,45.21588],[-93.61298,45.21185],[-93.64722,45.21166],[-93.64713,45.20359],[-93.65284,45.20355],[-93.65279,45.19952],[-93.6585,45.19949],[-93.65846,45.19545],[-93.66416,45.19542],[-93.66407,45.18735],[-93.65836,45.18739],[-93.65831,45.18335],[-93.65261,45.18338],[-93.65256,45.17935],[-93.64686,45.17938],[-93.64682,45.17535],[-93.64111,45.17538],[-93.64102,45.16731],[-93.64672,45.16728],[-93.64667,45.16324],[-93.65238,45.16321],[-93.65233,45.15917],[-93.65803,45.15914],[-93.65799,45.15511],[-93.6865,45.15494],[-93.68641,45.14687],[-93.69211,45.14683],[-93.69206,45.1428],[-93.69776,45.14276],[-93.69771,45.13873],[-93.70341,45.13869],[-93.70336,45.13466],[-93.70906,45.13462],[-93.70896,45.12655],[-93.71409,45.12652],[-93.71404,45.12245],[-93.72031,45.12241],[-93.72026,45.11841],[-93.72596,45.11838],[-93.72581,45.10627],[-93.7315,45.10623],[-93.7313,45.09009],[-93.73699,45.09006],[-93.73694,45.08602],[-93.74264,45.08599],[-93.74258,45.08195],[-93.75397,45.08188],[-93.75405,45.08591],[-93.76542,45.08584],[-93.7652,45.0697],[-93.7709,45.06966],[-93.76851,44.8903],[-93.60927,44.89126],[-93.60925,44.88905],[-93.52439,44.88947],[-93.52365,44.80364],[-93.43786,44.80979],[-93.34477,44.78525],[-93.24592,44.81373],[-93.20054,44.86147]]],"type":"Polygon"}}, -{"properties":{"name":"Hennepin County Orthoimagery (2022)","id":"Hennepin_Ortho_2022","url":"https://gis.hennepin.us/arcgis/services/Imagery/UTM_Aerial_2022/MapServer/WMSServer?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=1&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":false,"text":"Hennepin County GIS","url":"https://gis-hennepin.hub.arcgis.com/"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-93.20054,44.86147],[-93.1781,44.8865],[-93.17243,44.88651],[-93.17245,44.89458],[-93.18381,44.89456],[-93.18382,44.8986],[-93.18951,44.89859],[-93.18952,44.90666],[-93.19521,44.90665],[-93.19534,44.947],[-93.2018,44.94696],[-93.20189,44.95506],[-93.20673,44.95505],[-93.20702,45.03576],[-93.28101,45.03561],[-93.28115,45.06788],[-93.27548,45.06789],[-93.27566,45.10824],[-93.28136,45.10823],[-93.28137,45.10984],[-93.28426,45.10984],[-93.28427,45.11226],[-93.28708,45.11225],[-93.28711,45.11629],[-93.2928,45.11629],[-93.29289,45.13241],[-93.29858,45.1324],[-93.2986,45.13643],[-93.3043,45.13642],[-93.30491,45.14448],[-93.31005,45.14447],[-93.31007,45.14851],[-93.32147,45.14848],[-93.3215,45.15251],[-93.3272,45.1525],[-93.32723,45.15653],[-93.33863,45.1565],[-93.33866,45.16053],[-93.34436,45.16051],[-93.3444,45.16762],[-93.34599,45.16762],[-93.34599,45.16858],[-93.35011,45.16857],[-93.35014,45.1726],[-93.35585,45.17258],[-93.35586,45.17662],[-93.36158,45.17661],[-93.3616,45.18064],[-93.37301,45.18061],[-93.37304,45.18464],[-93.37874,45.18462],[-93.37877,45.18865],[-93.39018,45.18863],[-93.39021,45.19265],[-93.39591,45.19263],[-93.39594,45.19642],[-93.40762,45.1964],[-93.40767,45.20066],[-93.41309,45.20064],[-93.41315,45.20871],[-93.41886,45.20869],[-93.41892,45.21676],[-93.42463,45.21674],[-93.42466,45.22077],[-93.4532,45.22066],[-93.45323,45.2247],[-93.45894,45.22468],[-93.45898,45.22871],[-93.48753,45.22859],[-93.48756,45.23262],[-93.49327,45.2326],[-93.49334,45.24067],[-93.49905,45.24065],[-93.49909,45.24469],[-93.5048,45.24466],[-93.50484,45.24869],[-93.52768,45.24859],[-93.52761,45.24052],[-93.5219,45.24056],[-93.52187,45.23651],[-93.52757,45.23648],[-93.5275,45.22841],[-93.53321,45.22839],[-93.53325,45.23242],[-93.53896,45.2324],[-93.539,45.23643],[-93.54471,45.2364],[-93.54467,45.23237],[-93.55037,45.23234],[-93.55034,45.22831],[-93.56176,45.22825],[-93.56172,45.22422],[-93.57313,45.22417],[-93.5731,45.22012],[-93.59593,45.22001],[-93.59585,45.21194],[-93.60155,45.21191],[-93.6016,45.21594],[-93.61302,45.21588],[-93.61298,45.21185],[-93.64722,45.21166],[-93.64713,45.20359],[-93.65284,45.20355],[-93.65279,45.19952],[-93.6585,45.19949],[-93.65846,45.19545],[-93.66416,45.19542],[-93.66407,45.18735],[-93.65836,45.18739],[-93.65831,45.18335],[-93.65261,45.18338],[-93.65256,45.17935],[-93.64686,45.17938],[-93.64682,45.17535],[-93.64111,45.17538],[-93.64102,45.16731],[-93.64672,45.16728],[-93.64667,45.16324],[-93.65238,45.16321],[-93.65233,45.15917],[-93.65803,45.15914],[-93.65799,45.15511],[-93.6865,45.15494],[-93.68641,45.14687],[-93.69211,45.14683],[-93.69206,45.1428],[-93.69776,45.14276],[-93.69771,45.13873],[-93.70341,45.13869],[-93.70336,45.13466],[-93.70906,45.13462],[-93.70896,45.12655],[-93.71409,45.12652],[-93.71404,45.12245],[-93.72031,45.12241],[-93.72026,45.11841],[-93.72596,45.11838],[-93.72581,45.10627],[-93.7315,45.10623],[-93.7313,45.09009],[-93.73699,45.09006],[-93.73694,45.08602],[-93.74264,45.08599],[-93.74258,45.08195],[-93.75397,45.08188],[-93.75405,45.08591],[-93.76542,45.08584],[-93.7652,45.0697],[-93.7709,45.06966],[-93.76851,44.8903],[-93.60927,44.89126],[-93.60925,44.88905],[-93.52439,44.88947],[-93.52365,44.80364],[-93.43786,44.80979],[-93.34477,44.78525],[-93.24592,44.81373],[-93.20054,44.86147]]],"type":"Polygon"}}, +{"properties":{"name":"Hennepin County Orthoimagery (2022)","id":"Hennepin_Ortho_2022","url":"https://gis.hennepin.us/arcgis/services/Imagery/UTM_Aerial_2022/MapServer/WMSServer?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=0&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":false,"text":"Hennepin County GIS","url":"https://gis-hennepin.hub.arcgis.com/"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-93.20054,44.86147],[-93.1781,44.8865],[-93.17243,44.88651],[-93.17245,44.89458],[-93.18381,44.89456],[-93.18382,44.8986],[-93.18951,44.89859],[-93.18952,44.90666],[-93.19521,44.90665],[-93.19534,44.947],[-93.2018,44.94696],[-93.20189,44.95506],[-93.20673,44.95505],[-93.20702,45.03576],[-93.28101,45.03561],[-93.28115,45.06788],[-93.27548,45.06789],[-93.27566,45.10824],[-93.28136,45.10823],[-93.28137,45.10984],[-93.28426,45.10984],[-93.28427,45.11226],[-93.28708,45.11225],[-93.28711,45.11629],[-93.2928,45.11629],[-93.29289,45.13241],[-93.29858,45.1324],[-93.2986,45.13643],[-93.3043,45.13642],[-93.30491,45.14448],[-93.31005,45.14447],[-93.31007,45.14851],[-93.32147,45.14848],[-93.3215,45.15251],[-93.3272,45.1525],[-93.32723,45.15653],[-93.33863,45.1565],[-93.33866,45.16053],[-93.34436,45.16051],[-93.3444,45.16762],[-93.34599,45.16762],[-93.34599,45.16858],[-93.35011,45.16857],[-93.35014,45.1726],[-93.35585,45.17258],[-93.35586,45.17662],[-93.36158,45.17661],[-93.3616,45.18064],[-93.37301,45.18061],[-93.37304,45.18464],[-93.37874,45.18462],[-93.37877,45.18865],[-93.39018,45.18863],[-93.39021,45.19265],[-93.39591,45.19263],[-93.39594,45.19642],[-93.40762,45.1964],[-93.40767,45.20066],[-93.41309,45.20064],[-93.41315,45.20871],[-93.41886,45.20869],[-93.41892,45.21676],[-93.42463,45.21674],[-93.42466,45.22077],[-93.4532,45.22066],[-93.45323,45.2247],[-93.45894,45.22468],[-93.45898,45.22871],[-93.48753,45.22859],[-93.48756,45.23262],[-93.49327,45.2326],[-93.49334,45.24067],[-93.49905,45.24065],[-93.49909,45.24469],[-93.5048,45.24466],[-93.50484,45.24869],[-93.52768,45.24859],[-93.52761,45.24052],[-93.5219,45.24056],[-93.52187,45.23651],[-93.52757,45.23648],[-93.5275,45.22841],[-93.53321,45.22839],[-93.53325,45.23242],[-93.53896,45.2324],[-93.539,45.23643],[-93.54471,45.2364],[-93.54467,45.23237],[-93.55037,45.23234],[-93.55034,45.22831],[-93.56176,45.22825],[-93.56172,45.22422],[-93.57313,45.22417],[-93.5731,45.22012],[-93.59593,45.22001],[-93.59585,45.21194],[-93.60155,45.21191],[-93.6016,45.21594],[-93.61302,45.21588],[-93.61298,45.21185],[-93.64722,45.21166],[-93.64713,45.20359],[-93.65284,45.20355],[-93.65279,45.19952],[-93.6585,45.19949],[-93.65846,45.19545],[-93.66416,45.19542],[-93.66407,45.18735],[-93.65836,45.18739],[-93.65831,45.18335],[-93.65261,45.18338],[-93.65256,45.17935],[-93.64686,45.17938],[-93.64682,45.17535],[-93.64111,45.17538],[-93.64102,45.16731],[-93.64672,45.16728],[-93.64667,45.16324],[-93.65238,45.16321],[-93.65233,45.15917],[-93.65803,45.15914],[-93.65799,45.15511],[-93.6865,45.15494],[-93.68641,45.14687],[-93.69211,45.14683],[-93.69206,45.1428],[-93.69776,45.14276],[-93.69771,45.13873],[-93.70341,45.13869],[-93.70336,45.13466],[-93.70906,45.13462],[-93.70896,45.12655],[-93.71409,45.12652],[-93.71404,45.12245],[-93.72031,45.12241],[-93.72026,45.11841],[-93.72596,45.11838],[-93.72581,45.10627],[-93.7315,45.10623],[-93.7313,45.09009],[-93.73699,45.09006],[-93.73694,45.08602],[-93.74264,45.08599],[-93.74258,45.08195],[-93.75397,45.08188],[-93.75405,45.08591],[-93.76542,45.08584],[-93.7652,45.0697],[-93.7709,45.06966],[-93.76851,44.8903],[-93.60927,44.89126],[-93.60925,44.88905],[-93.52439,44.88947],[-93.52365,44.80364],[-93.43786,44.80979],[-93.34477,44.78525],[-93.24592,44.81373],[-93.20054,44.86147]]],"type":"Polygon"}}, {"properties":{"name":"Minnesota Composite Image Service","id":"Minnesota-Composite-Image-Service","url":"https://imageserver.gisdata.mn.gov/cgi-bin/mncomp?LAYERS=mncomp&STYLES=&CRS={proj}&BBOX={bbox}&FORMAT=image/jpeg&WIDTH={width}&HEIGHT={height}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap","attribution":{"required":false,"text":"MnGeo","url":"https://www.mngeo.state.mn.us/chouse/wms/composite_image.html"},"type":"wms","category":"photo","min_zoom":3,"max_zoom":20},"type":"Feature","geometry":{"coordinates":[[[-97.17831,48.87603],[-97.1904,48.81522],[-97.15809,48.81035],[-97.18153,48.79821],[-97.08987,48.68402],[-97.17544,48.56222],[-97.13912,48.55541],[-97.16595,48.54825],[-97.12678,48.5202],[-97.16268,48.47779],[-97.12817,48.47437],[-97.15064,48.44082],[-97.12483,48.4419],[-97.14588,48.43116],[-97.12259,48.41793],[-97.15398,48.41814],[-97.13118,48.40729],[-97.16339,48.39287],[-97.13335,48.38221],[-97.15627,48.36559],[-97.11224,48.29648],[-97.14504,48.26877],[-97.1207,48.22476],[-97.12452,48.22318],[-97.1372,48.22696],[-97.14967,48.22316],[-97.1522,48.21964],[-97.13907,48.22196],[-97.12289,48.2165],[-97.11785,48.20974],[-97.13931,48.21676],[-97.12929,48.20839],[-97.14752,48.17058],[-97.12098,48.15956],[-97.14652,48.14223],[-97.07227,48.04808],[-97.02317,47.87399],[-96.97416,47.82335],[-96.99169,47.80842],[-96.93499,47.76706],[-96.93113,47.7154],[-96.85096,47.5983],[-96.87184,47.41882],[-96.8376,47.38899],[-96.85847,47.36769],[-96.829,47.32762],[-96.84488,47.19282],[-96.82192,47.18425],[-96.84147,47.15185],[-96.81257,47.03859],[-96.83956,47.00674],[-96.79177,46.92847],[-96.75327,46.92457],[-96.80255,46.81153],[-96.77546,46.76676],[-96.79821,46.62933],[-96.74722,46.58235],[-96.72201,46.43999],[-96.59961,46.33014],[-96.59269,46.17522],[-96.55452,46.08399],[-96.58118,45.82302],[-96.6626,45.73869],[-96.83866,45.64752],[-96.85776,45.60597],[-96.69255,45.41735],[-96.5218,45.37565],[-96.45314,45.30079],[-96.45306,43.50038],[-93.84857,43.49963],[-91.21772,43.50064],[-91.23187,43.58183],[-91.26899,43.61659],[-91.24414,43.77468],[-91.43253,43.99684],[-91.59208,44.03138],[-91.72156,44.13035],[-91.87517,44.20058],[-91.91863,44.32268],[-91.96682,44.36399],[-92.23086,44.4445],[-92.33612,44.55401],[-92.54807,44.5678],[-92.56944,44.60355],[-92.62148,44.61505],[-92.63211,44.64904],[-92.80786,44.75085],[-92.75065,44.93731],[-92.76207,45.02433],[-92.80313,45.06157],[-92.74092,45.11296],[-92.76188,45.28702],[-92.65043,45.39852],[-92.64651,45.44035],[-92.7456,45.55302],[-92.88376,45.57549],[-92.8692,45.71758],[-92.78463,45.7642],[-92.70771,45.89491],[-92.55194,45.95166],[-92.52519,45.98387],[-92.46936,45.97382],[-92.42856,46.02425],[-92.35177,46.01569],[-92.33292,46.06271],[-92.29404,46.07439],[-92.2913,46.66815],[-92.2071,46.65195],[-92.1761,46.68635],[-92.2047,46.70405],[-92.1463,46.71595],[-92.1166,46.74865],[-92.01631,46.70598],[-92.08868,46.79367],[-91.7799,46.94341],[-91.57352,47.09003],[-91.46563,47.13124],[-91.04681,47.45632],[-90.7776,47.60573],[-90.43711,47.73164],[-89.97463,47.83056],[-89.75663,47.9041],[-89.68041,47.96408],[-89.63918,47.95373],[-89.62363,47.99464],[-89.57027,47.98571],[-89.49176,48.00536],[-89.5698,47.99899],[-89.61071,48.01786],[-89.65088,48.00354],[-89.77537,48.02279],[-89.89721,47.98751],[-89.99383,48.02802],[-90.02334,48.08468],[-90.13579,48.11215],[-90.3743,48.09092],[-90.4674,48.10875],[-90.55671,48.09594],[-90.57969,48.12381],[-90.75159,48.091],[-90.79823,48.1369],[-90.77794,48.16385],[-90.83641,48.17704],[-90.8393,48.23957],[-90.88576,48.24596],[-91.08248,48.18116],[-91.26678,48.07884],[-91.42958,48.04866],[-91.48819,48.06839],[-91.56752,48.0438],[-91.55912,48.1086],[-91.63993,48.09712],[-91.68212,48.12251],[-91.71176,48.11466],[-91.71537,48.19951],[-91.86437,48.20696],[-91.89311,48.23799],[-91.95836,48.23314],[-91.95411,48.25227],[-92.00653,48.26542],[-92.00012,48.3211],[-92.05523,48.35937],[-92.26256,48.35492],[-92.30618,48.31625],[-92.26959,48.24819],[-92.36992,48.22029],[-92.46978,48.3521],[-92.45644,48.41409],[-92.50748,48.44799],[-92.65623,48.43648],[-92.71269,48.46299],[-92.69868,48.49485],[-92.62702,48.50328],[-92.63489,48.54256],[-92.72842,48.53938],[-92.95002,48.60835],[-92.9548,48.63154],[-93.17839,48.62301],[-93.25466,48.64282],[-93.46548,48.59164],[-93.46739,48.54646],[-93.79338,48.51632],[-93.84436,48.63022],[-94.22422,48.64947],[-94.29121,48.70782],[-94.41584,48.71098],[-94.45239,48.69241],[-94.64538,48.74403],[-94.69441,48.78945],[-94.68347,48.88413],[-94.81627,49.32141],[-94.9574,49.37021],[-95.05831,49.35326],[-95.1534,49.38449],[-95.1532,48.99888],[-97.22956,49.00046],[-97.23421,48.94739],[-97.17831,48.87603]]],"type":"Polygon"}}, {"properties":{"name":"City of Bozeman Aerial Photography (2021)","id":"Bozeman_MT_2021","url":"https://gisweb.bozeman.net/image/services/COB_20210417_WGS84_WebMercator/ImageServer/WMSServer?FORMAT=image/jpeg&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap&LAYERS=0&STYLES=&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}","attribution":{"required":false,"text":"City of Bozeman GIS Department","url":"https://public-bozeman.opendata.arcgis.com/"},"type":"wms","category":"photo","max_zoom":19},"type":"Feature","geometry":{"coordinates":[[[-111.11853,45.75121],[-111.1187,45.73664],[-111.14471,45.73659],[-111.14494,45.71462],[-111.13456,45.71467],[-111.13509,45.68218],[-111.15272,45.68215],[-111.15272,45.67971],[-111.16263,45.6797],[-111.1626,45.67032],[-111.1552,45.67015],[-111.15509,45.6513],[-111.13548,45.65113],[-111.13531,45.63794],[-111.12515,45.63096],[-111.10951,45.63087],[-111.10948,45.6237],[-111.10432,45.62367],[-111.08871,45.61294],[-111.07852,45.61293],[-111.07677,45.61067],[-111.07671,45.5802],[-111.04551,45.59404],[-111.02002,45.59389],[-111.02004,45.60568],[-111.01056,45.60572],[-111.01058,45.62009],[-111.00105,45.62006],[-111.00103,45.6273],[-110.97011,45.62733],[-110.97007,45.6382],[-110.96011,45.63817],[-110.95998,45.65255],[-110.95475,45.65255],[-110.95404,45.69923],[-110.96973,45.69994],[-110.96998,45.7036],[-110.96986,45.73627],[-111.04063,45.73675],[-111.04051,45.74041],[-111.06631,45.74044],[-111.06635,45.74662],[-111.06888,45.75132],[-111.11853,45.75121]]],"type":"Polygon"}}, {"properties":{"name":"Mecklenburg County Orthoimagery (2021)","id":"Mecklenburg_NC_2021","url":"https://polaris3g.mecklenburgcountync.gov/polarisv/rest/services/aerial2021/MapServer/export?f=image&format=jpg&layers=&bbox={bbox}&bboxSR={wkid}&imageSR={wkid}&size={width},{height}&foo={proj}","attribution":{"required":false,"text":"Mecklenburg County GIS","url":"https://www.mecknc.gov/LUESA/GIS/Pages/GIS-Data-Center.aspx"},"type":"wms","category":"historicphoto","max_zoom":21},"type":"Feature","geometry":{"coordinates":[[[-80.93764,35.5219],[-80.93729,35.50739],[-80.95503,35.50709],[-80.95361,35.44911],[-80.97136,35.4488],[-80.96995,35.39079],[-80.98767,35.3905],[-80.98624,35.33248],[-81.00395,35.33219],[-81.00323,35.30318],[-81.02092,35.30288],[-81.01733,35.15784],[-81.05265,35.15724],[-81.0512,35.09923],[-81.06884,35.09892],[-81.06737,35.04091],[-81.01446,35.0418],[-81.01482,35.0563],[-80.97954,35.05689],[-80.97989,35.07139],[-80.96225,35.07168],[-80.9626,35.08619],[-80.92731,35.08675],[-80.92697,35.07225],[-80.90932,35.07253],[-80.90897,35.05803],[-80.89134,35.0583],[-80.89066,35.02929],[-80.87303,35.02957],[-80.8727,35.01506],[-80.85507,35.01533],[-80.85474,35.00083],[-80.81948,35.00136],[-80.8198,35.01587],[-80.78454,35.0164],[-80.78486,35.0309],[-80.74959,35.03142],[-80.74989,35.04593],[-80.73226,35.04618],[-80.73257,35.06068],[-80.71492,35.06094],[-80.71523,35.07544],[-80.69758,35.07569],[-80.69789,35.0902],[-80.66259,35.09069],[-80.66288,35.1052],[-80.64523,35.10544],[-80.64553,35.11994],[-80.62787,35.12018],[-80.62816,35.13469],[-80.6105,35.13493],[-80.61079,35.14943],[-80.59313,35.14966],[-80.59341,35.16417],[-80.57575,35.1644],[-80.57602,35.17891],[-80.55836,35.17914],[-80.55864,35.19365],[-80.54096,35.19387],[-80.54151,35.22288],[-80.57687,35.22242],[-80.57714,35.23695],[-80.59483,35.2367],[-80.59511,35.25121],[-80.63048,35.25074],[-80.63077,35.26524],[-80.64846,35.265],[-80.64875,35.27951],[-80.66644,35.27927],[-80.66733,35.32278],[-80.68503,35.32254],[-80.68594,35.36606],[-80.72134,35.36556],[-80.72166,35.38006],[-80.73936,35.37981],[-80.74061,35.43783],[-80.75833,35.43757],[-80.75928,35.48108],[-80.77701,35.48082],[-80.77764,35.50984],[-80.81313,35.50931],[-80.81345,35.52381],[-80.93764,35.5219]]],"type":"Polygon"}}, From c7089c27a0e768e227a1c046dab9fdd04efec389 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sat, 2 Dec 2023 01:46:50 +0100 Subject: [PATCH 34/99] UI: fix #1720 --- public/css/index-tailwind-output.css | 4 ++++ src/UI/AllThemesGui.svelte | 4 +--- src/UI/Base/Dropdown.svelte | 3 ++- src/UI/InputElement/LanguagePicker.svelte | 8 +++++--- src/index.css | 4 ++++ 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 97787d023..26b1638ae 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -2704,6 +2704,10 @@ a.link-underline { min-height: 8rem; } +.max-w-full { + max-width: 100%; +} + .hover\:bg-indigo-200:hover { --tw-bg-opacity: 1; background-color: rgb(199 210 254 / var(--tw-bg-opacity)); diff --git a/src/UI/AllThemesGui.svelte b/src/UI/AllThemesGui.svelte index beaa6442e..a764a7bcd 100644 --- a/src/UI/AllThemesGui.svelte +++ b/src/UI/AllThemesGui.svelte @@ -29,10 +29,8 @@
-
- -
diff --git a/src/UI/Base/Dropdown.svelte b/src/UI/Base/Dropdown.svelte index 71a94a08f..3bd0106f5 100644 --- a/src/UI/Base/Dropdown.svelte +++ b/src/UI/Base/Dropdown.svelte @@ -24,8 +24,9 @@ selectAppropriateValue() } } + export let cls : string = undefined - {value.setData(e.srcElement.value)}}> diff --git a/src/UI/InputElement/LanguagePicker.svelte b/src/UI/InputElement/LanguagePicker.svelte index 15329a48c..80414f746 100644 --- a/src/UI/InputElement/LanguagePicker.svelte +++ b/src/UI/InputElement/LanguagePicker.svelte @@ -8,6 +8,7 @@ import Locale from "../i18n/Locale"; import { LanguageIcon } from "@babeard/svelte-heroicons/solid"; import Dropdown from "../Base/Dropdown.svelte"; + import { twMerge } from "tailwind-merge" /** * Languages one can choose from @@ -33,13 +34,14 @@ let current = Locale.language; + export let clss : string = undefined {#if availableLanguages?.length > 1} -
+ - - + + {#if preferredFiltered} {#each preferredFiltered as language}