From b68bf7b95029a3161b5471daebf12997c767349f Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 09:34:00 +0200 Subject: [PATCH 1/5] Download cached features as geojson --- InitUiElements.ts | 2 ++ State.ts | 2 ++ UI/BigComponents/LayerSelection.ts | 5 +++++ UI/GeoJsonExport.ts | 15 +++++++++++++++ Utils.ts | 8 ++++++++ 5 files changed, 32 insertions(+) create mode 100644 UI/GeoJsonExport.ts diff --git a/InitUiElements.ts b/InitUiElements.ts index 0f1143eba7..97dd2b02c4 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -427,6 +427,8 @@ export class InitUiElements { state.locationControl, state.selectedElement); + State.state.featurePipeline = source; + new ShowDataLayer(source.features, State.state.leafletMap, State.state.layoutToUse); const selectedFeatureHandler = new SelectedFeatureHandler(Hash.hash, State.state.selectedElement, source, State.state.osmApiFeatureSource); diff --git a/State.ts b/State.ts index 8e4322d654..7793485aa3 100644 --- a/State.ts +++ b/State.ts @@ -19,6 +19,7 @@ import TitleHandler from "./Logic/Actors/TitleHandler"; import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader"; import {Relation} from "./Logic/Osm/ExtractRelations"; import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource"; +import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; /** * Contains the global state: a bunch of UI-event sources @@ -95,6 +96,7 @@ export default class State { public readonly featureSwitchIsDebugging: UIEventSource; public readonly featureSwitchShowAllQuestions: UIEventSource; public readonly featureSwitchApiURL: UIEventSource; + public readonly featurePipeline: FeaturePipeline; /** diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index e282947096..11237fa329 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -7,6 +7,8 @@ import Translations from "../i18n/Translations"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import {Translation} from "../i18n/Translation"; +import {SubtleButton} from "../Base/SubtleButton"; +import {exportAsGeoJson} from "../GeoJsonExport"; /** * Shows the panel with all layers and a toggle for each of them @@ -74,6 +76,9 @@ export default class LayerSelection extends Combine { ); } + const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") + downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) // TODO: Define this + checkboxes.push(downloadButton) super(checkboxes) this.SetStyle("display:flex;flex-direction:column;") diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts new file mode 100644 index 0000000000..c18baed17e --- /dev/null +++ b/UI/GeoJsonExport.ts @@ -0,0 +1,15 @@ +import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; +import {Utils} from "../Utils"; + +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: {metadata?: boolean}) { + let defaults = { + metadata: false + } + options = Utils.setDefaults(options, defaults); + // Select all features, ignore the freshness and other data + // TODO: Remove mapcomplete metadata (starting with underscore) + let featureList: JSON[] = featurePipeline? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + let geojson = {type: "FeatureCollection", features: featureList} + + Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); +} diff --git a/Utils.ts b/Utils.ts index 05ebcbaabc..418f1d1111 100644 --- a/Utils.ts +++ b/Utils.ts @@ -447,6 +447,14 @@ export class Utils { b: parseInt(hex.substr(5, 2), 16), } } + + public static setDefaults(options, defaults){ + let result = {}; + for (let key of defaults){ + result[key] = key in options ? options[key] : defaults[key]; + } + return result; + } } export interface TileRange { From bd07eed4824afb03d09ebf98c2fab4ce7a8b7f91 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 09:58:17 +0200 Subject: [PATCH 2/5] Remove MapComplete metadata from featurelist --- UI/GeoJsonExport.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts index c18baed17e..68037eee3e 100644 --- a/UI/GeoJsonExport.ts +++ b/UI/GeoJsonExport.ts @@ -1,14 +1,31 @@ import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; import {Utils} from "../Utils"; -export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: {metadata?: boolean}) { +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { metadata?: boolean }) { let defaults = { metadata: false } options = Utils.setDefaults(options, defaults); // Select all features, ignore the freshness and other data - // TODO: Remove mapcomplete metadata (starting with underscore) - let featureList: JSON[] = featurePipeline? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + + function removeMetaData(featureList: JSON[]) { + for (let i=0; i < featureList.length; i++) { + let feature = featureList[i]; + for (let property in feature.properties) { + if (property[0] == "_") { + delete featureList[i]["properties"][property]; + } + } + } + return featureList; + } + + // Remove the metadata of MapComplete (all properties starting with an underscore) + if (!options.metadata) { + removeMetaData(featureList); + } + let geojson = {type: "FeatureCollection", features: featureList} Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); From e7ef2fb6d8116fae7edfea16b0488b00d56395c8 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 10:56:30 +0200 Subject: [PATCH 3/5] Updated documentation --- UI/BigComponents/LayerSelection.ts | 2 +- UI/GeoJsonExport.ts | 21 ++++++++++++++------- Utils.ts | 7 +++---- tslint.json | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index 11237fa329..900be93489 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -77,7 +77,7 @@ export default class LayerSelection extends Combine { } const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") - downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) // TODO: Define this + downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) checkboxes.push(downloadButton) super(checkboxes) diff --git a/UI/GeoJsonExport.ts b/UI/GeoJsonExport.ts index 68037eee3e..d3e5dc5d68 100644 --- a/UI/GeoJsonExport.ts +++ b/UI/GeoJsonExport.ts @@ -1,14 +1,25 @@ import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; import {Utils} from "../Utils"; -export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { metadata?: boolean }) { +/** + * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) + * @param featurePipeline The FeaturePipeline you want to export + * @param options The options object + * @param options.metadata True if you want to include the MapComplete metadata, false otherwise + */ +export function exportAsGeoJson(featurePipeline: FeaturePipeline, options: { metadata?: boolean} = {}) { let defaults = { - metadata: false + metadata: false, } options = Utils.setDefaults(options, defaults); + // Select all features, ignore the freshness and other data let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; + /** + * Removes the metadata of MapComplete (all properties starting with an underscore) + * @param featureList JsonList containing features, output object + */ function removeMetaData(featureList: JSON[]) { for (let i=0; i < featureList.length; i++) { let feature = featureList[i]; @@ -18,13 +29,9 @@ export function exportAsGeoJson(featurePipeline: FeaturePipeline, options?: { me } } } - return featureList; } - // Remove the metadata of MapComplete (all properties starting with an underscore) - if (!options.metadata) { - removeMetaData(featureList); - } + if (!options.metadata) removeMetaData(featureList); let geojson = {type: "FeatureCollection", features: featureList} diff --git a/Utils.ts b/Utils.ts index 418f1d1111..683e7a8f94 100644 --- a/Utils.ts +++ b/Utils.ts @@ -449,11 +449,10 @@ export class Utils { } public static setDefaults(options, defaults){ - let result = {}; - for (let key of defaults){ - result[key] = key in options ? options[key] : defaults[key]; + for (let key in defaults){ + if (!(key in options)) options[key] = defaults[key]; } - return result; + return options; } } diff --git a/tslint.json b/tslint.json index 6a204a045b..85c7437ac6 100644 --- a/tslint.json +++ b/tslint.json @@ -1,5 +1,5 @@ { - "defaultSeverity": "error", + "defaultSeverity": "warn", "extends": [ "tslint:recommended", "tslint-no-circular-imports" From 62925a89ba333eb654ac67bb5084788e466050f0 Mon Sep 17 00:00:00 2001 From: Arno Deceuninck Date: Thu, 15 Jul 2021 11:13:00 +0200 Subject: [PATCH 4/5] Text in translation file + refactor --- {UI => Logic/FeatureSource}/GeoJsonExport.ts | 4 ++-- UI/BigComponents/LayerSelection.ts | 4 ++-- langs/en.json | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) rename {UI => Logic/FeatureSource}/GeoJsonExport.ts (93%) diff --git a/UI/GeoJsonExport.ts b/Logic/FeatureSource/GeoJsonExport.ts similarity index 93% rename from UI/GeoJsonExport.ts rename to Logic/FeatureSource/GeoJsonExport.ts index d3e5dc5d68..541e103730 100644 --- a/UI/GeoJsonExport.ts +++ b/Logic/FeatureSource/GeoJsonExport.ts @@ -1,5 +1,5 @@ -import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline"; -import {Utils} from "../Utils"; +import FeaturePipeline from "./FeaturePipeline"; +import {Utils} from "../../Utils"; /** * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) diff --git a/UI/BigComponents/LayerSelection.ts b/UI/BigComponents/LayerSelection.ts index 900be93489..c48b361633 100644 --- a/UI/BigComponents/LayerSelection.ts +++ b/UI/BigComponents/LayerSelection.ts @@ -8,7 +8,7 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import {Translation} from "../i18n/Translation"; import {SubtleButton} from "../Base/SubtleButton"; -import {exportAsGeoJson} from "../GeoJsonExport"; +import {exportAsGeoJson} from "../../Logic/FeatureSource/GeoJsonExport"; /** * Shows the panel with all layers and a toggle for each of them @@ -76,7 +76,7 @@ export default class LayerSelection extends Combine { ); } - const downloadButton = new SubtleButton("./assets/svg/floppy.svg", "Download visible data as geojson") + const downloadButton = new SubtleButton("./assets/svg/floppy.svg", Translations.t.general.layerSelection.downloadGeojson.Clone()) downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) checkboxes.push(downloadButton) diff --git a/langs/en.json b/langs/en.json index 7f327653c5..b604850f8f 100644 --- a/langs/en.json +++ b/langs/en.json @@ -147,7 +147,8 @@ "loginOnlyNeededToEdit": "if you want to edit the map", "layerSelection": { "zoomInToSeeThisLayer": "Zoom in to see this layer", - "title": "Select layers" + "title": "Select layers", + "downloadGeojson": "Download layer features as geojson" }, "weekdays": { "abbreviations": { From 294bdbfd9247ef99f5798881cbb5fadb76f0bad4 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 16 Jul 2021 00:49:50 +0200 Subject: [PATCH 5/5] Add missing license info --- assets/svg/license_info.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 1ef8f94c8e..db044b683d 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -582,5 +582,15 @@ "sources": [ "https://www.mapillary.com/" ] + }, + { + "authors": [ + "The Tango! Desktop Project" + ], + "path": "floppy.svg", + "license": "CC0", + "sources": [ + "https://commons.wikimedia.org/wiki/File:Media-floppy.svg" + ] } ] \ No newline at end of file